Декоратор - это не более (или менее), чем вызываемый объект, возвращающий вызываемый элемент [0] aka
@foo
def bar():
...
точно так же, как:
def bar():
...
bar = foo(bar)
Существуют различные варианты чтобы «умничать» декораторы, lru_cache делает это довольно просто:
- оборачивает декорированную функцию в
wrapper
функцию - , а затем устанавливает атрибуты этой функции
wrapper
- и возвращает оболочку (поменяв оригинальную функцию для оболочки)
import functools
def foo(fn):
@functools.wraps(fn)
def wrapper(*args, **kwargs):
return fn(*args, **kwargs)
wrapper.thing = 'yay'
return wrapper
@foo
def bar(): ...
print(bar.thing)
напечатает yay
.
[0] или даже не вызывается, как в случае @property
или @cached_property
.