Короткий ответ
Такой декоратор строится как фабрика декораторов с тремя уровнями вложенности: внешняя функция принимает параметры, средняя — декорируемую функцию, а самая внутренняя обёртка выполняет работу. Параметры попадают в обёртку через замыкание.
Как это работает подробнее
- Три уровня. Обычный декоратор имеет два уровня, а параметризованный — три, потому что параметры должны «дойти» до внутренних функций через замыкание.
- Синтаксис. Запись
@decorator(params)означает, что сначала вызываетсяdecorator(params), возвращающая декоратор, который затем применяется к функции:func = decorator(params)(func). - Роли функций. Внешняя функция принимает и запоминает параметры, средний уровень принимает декорируемую функцию, а внутренний
wrapperработает при вызове. - Фабрика декораторов. Паттерн удобен, когда нужна одна и та же логика обёртки, применяемая с разными настройками.
Пример кода
Декоратор repeat, повторяющий вызов функции
from functools import wraps
def repeat(times):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
for _ in range(times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat(3)
def say(word):
print(word)
say('Привет') # 'Привет' выведется три разаЧто использовать на практике
- Параметризация. Используй фабрику декораторов, когда одна и та же обёртка нужна с разными значениями настроек.
- Комбинация с wraps. На внутреннем уровне не забывай про
@wraps(func), чтобы сохранять метаданные функции. - Аргументы обёртки. Внутренняя обёртка должна принимать произвольные позиционные и именованные аргументы исходной функции и передавать их ей при вызове.
Подводные камни
- Пропущенный уровень. Без среднего уровня декоратор будет применён к функции неверно, и вызов завершится ошибкой.
- Неверная запись. Использование
@decoratorвместо@decorator(params)нарушает ожидаемую сигнатуру и ломает вызов. - Замыкание параметров. Параметры должны захватываться замыканием внешней функции, иначе обёртка не сможет их использовать.
Как отвечать на собеседовании
- Объясни, что параметризованный декоратор — это фабрика декораторов с тремя уровнями вложенности → разбери синтаксис
@repeat(3)какrepeat(3)(func)→ покажи, как параметры через замыкание попадают в обёртку → приведи пример с повторением вызова и упомяни@wraps.