Синтаксис @decorator
является просто синтаксическим сахаром, поэтому оба примера ведут себя одинаково. Это также означает, что любое различие между ними может быть не таким значимым, как вы думали.
Хотя вы можете использовать inspect
, чтобы прочитать ваш сценарий и увидеть, как декоратор вызывался в приведенном выше кадре.
import inspect
def decorate(func):
# See explanation below
lines = inspect.stack(context=2)[1].code_context
decorated = any(line.startswith('@') for line in lines)
print(func.__name__, 'was decorated with "@decorate":', decorated)
return func
Обратите внимание, что мы должны были указать context=2
для функции inspect.stack
. Аргумент context
указывает, сколько строк кода вокруг текущей строки должно быть возвращено. В некоторых конкретных случаях, например, при украшении подкласса, текущая строка была в объявлении класса вместо декоратора. Точная причина такого поведения была исследована здесь.
Пример
@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
Протест
Есть еще несколько угловых случаев, которые мы едва ли можем преодолеть, такие как разрывы строк между декоратором и объявлением класса.
# This will fail
@decorate
class MyDict(dict):
pass