Eman Ismail
Eman Ismail

Reputation: 133

python- How can I get value passed to class decorators?

I have a class decorator that have two arguments as following:

def decoratorB(x: int, y: int): 
    def inner(cls):
        def no_wrap(*args, **kwargs):
            return cls(*args, **kwargs)

        no_wrap.x = x
        no_wrap.y = y
        return no_wrap

    return inner

and I used it to decorate a class in this way:

@decoratorB(x=100, y=-100)
class ClassB():
    def func(self, name):
        pass

How can I get the values of x and y from an object of ClassB?

obj = ClassB()

Thanks in advance.

Upvotes: 3

Views: 120

Answers (1)

12944qwerty
12944qwerty

Reputation: 2007

Try printing the dir of ClassB vs obj.

>>> print(dir(obj))
# ['__class__', ..., 'func']

>>> print(dir(ClassB))
# ['__annotations__', ..., 'x', 'y']

Notice how x and y are only found in ClassB as a class, not as an instance of it. Also notice how func is only found in the instance. This is because of how you defined the decorator. We are applying the attributes to no_wrap instead of the obj itself.
You can either manually set the attributes in __init__ or change the decorator.

@decoratorB(x=100, y=-100)
class ClassB:
    def __init__(self):
        for attr in dir(ClassB)[35:]: # Get rid of builtin methods so we don't override
            setattr(self, attr, getattr(ClassB, attr, None))
    def func(self, name):
        pass

>>> print(dir(Class())
# ['__class__', ..., 'func', 'x', 'y']

Edit: Thanks to chepner's comment up there, I realized we could just rewrite the decorator instead.

We should take the cls object and assign the values to the object instead of a "copy".

def decoratorB(x: int, y: int): 
    def inner(cls):
        new = cls
        new.x = x
        new.y = y
        return new
    return inner

>>> print(dir(ClassB))
# ['__class__', 'func', 'x', 'y']

>>> print(dir(ClassB()))
# ['__class__', 'func', 'x', 'y']

Upvotes: 1

Related Questions