Урок курса
Декораторы в Python: функции, @ и параметры
Python для профессионаловДекоратор принимает вызываемый объект и возвращает другой вызываемый объект. Это позволяет добавить логирование, проверку прав, кэширование или измерение времени, не смешивая служебную логику с телом функции.
from functools import wraps
def traced(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(f"call {func.__name__}")
return func(*args, **kwargs)
return wrapper
@traced
def add(a: int, b: int) -> int:
return a + b
Запись @traced эквивалентна add = traced(add). Декоратор выполняется в момент определения функции, а wrapper — при каждом вызове.
Почему нужен functools.wraps
Без @wraps(func) наружу торчит имя и документация обёртки. Это мешает логам, introspection, генерации документации и некоторым фреймворкам. wraps копирует важные метаданные и сохраняет ссылку __wrapped__ на исходную функцию.
Обёртка почти всегда принимает *args, **kwargs, чтобы не ломать разные сигнатуры. При этом типизацию сложных универсальных декораторов лучше оформлять через ParamSpec и TypeVar; простая аннотация Callable[..., Any] скрывает ошибки аргументов.
Порядок нескольких декораторов важен. В записи @a над @b сначала создаётся b(func), затем a(...). При вызове внешняя обёртка a срабатывает первой.
Декоратор с параметрами
Если у декоратора есть настройка, появляется ещё один уровень функции — фабрика декораторов.
from functools import wraps
def repeat(times: int):
if times < 1:
raise ValueError("times must be positive")
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
result = None
for _ in range(times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator
Теперь @repeat(3) сначала вызывает фабрику, получает декоратор и только затем оборачивает функцию. Не прячьте в декоратор критичное поведение без явного имени: транзакции, retry и авторизация должны оставаться наблюдаемыми и тестируемыми.
Попробуйте решить
Зачем обычно добавляют @functools.wraps к wrapper-функции?
Продолжить с проверкой и прогрессом
Откройте интерактивный раннер с заданиями урока.
