Search code examples
pythonpython-internals

When does class level decorator decorates?


I have created a decorator to decorate all instance methods of a class. I have written following code to do so.

def debug(func):
    msg = func.__name__

    @wraps(func)
    def wrapper(*args, **kwargs):
        print(msg)
        return func(*args, **kwargs)
    return wrapper 

# Decorator for all the methods in a class
def debugmethods(cls):
    for key, val in vars(cls).items():
        if callable(val):
            setattr(cls, key, debug(val))
    return cls

@debugmethods
class Spam:
    def foo(self):
        pass

    def bar(self):
        pass

Now I am trying to understand how this works, I mean when will this decoration happen and how can I check that?

a) It already happened?

b) When I access Spam class for the first time? For e.g.

for key, val in Spam.__dict__.items():
        print(key, val)

c) When I instantiate Spam class for the first time? For e.g.

 spam = Spam()
 for key, val in Spam.__dict__.items():
     print(key, val)

Solution

  • This is actually easily seen in action if you add a few print lines:

    print('Deocrator is being defined')
    def deco(cls):
        print('Decorator is called')
        cls.decorated = True
        return cls
    
    print('Foo is being defined')
    @deco
    class Foo:
        print('Foo class attributes are being set')
        def __init__(self):
            print('Foo is being instantiated')
    
    print('Foo class is being referenced in main script')
    print(f'Foo is decorated: {Foo.decorated}')
    print('Foo instance is being created in main script')
    print(Foo())
    

    Result:

    Deocrator is being defined
    Foo is being defined
    Foo class attributes are being set
    Decorator is called    # <--- decoration happens immediately after definition of Foo
    Foo class is being referenced in main script
    Foo is decorated: True
    Foo instance is being created in main script
    Foo is being instantiated
    <__main__.Foo object at 0x00789150>
    

    In short, the answer is much like what @jonrsharpe said, it already happened. Just figure the visual would help.