In the following minimal example
decorate is called two times. First using
@decorate, second by normal function call
def decorate(func): print(func.__name__) return func @decorate def bar(): pass decorate(bar)
Is it possible to see inside of
decorate if the call was invoked by using
@decorate or as a normal function call?
@decorator syntax is just syntactic sugar, thus both examples have identical behaviour. This also means whatever distinction you are doing between them might not be as meaningful as you thought.
Although, you can use
inspect to read your script and see how the decorator was called in the above frame.
import inspect def decorate(func): # See explanation below lines = inspect.stack(context=2).code_context decorated = any(line.startswith('@') for line in lines) print(func.__name__, 'was decorated with "@decorate":', decorated) return func
Note that we had to specify
context=2 to the
inspect.stack function. The
context argument indicates how many lines of code around the current line must be returned. In some specific cases, such as when decorating a subclass, the current line was on the class declaration instead of the decorator. The exact reason for this behaviour has been explored here.
@decorate def bar(): pass def foo(): pass foo = decorate(foo) @decorate class MyDict(dict): pass
bar was decorated with "@decorate": True foo was decorated with "@decorate": False MyDict was decorated with "@decorate": True
There are still some corner cases that we can hardly overcome such as linebreaks between the decorator and a class declaration.
# This will fail @decorate class MyDict(dict): pass