2025, Nov 27 06:01
Где применять functools.wraps в фабриках декораторов Python
Разбираем правильное место для functools.wraps в фабриках декораторов Python: почему это важно, как исправить код и избежать ошибок. Пошаговый пример.
Фабрики декораторов — удобный способ задавать параметры поведения, но они часто поднимают один и тот же вопрос: где именно следует применять functools.wraps? Если вы видели лишь базовые примеры декораторов в официальной документации, появление фабрики может вызвать сомнения.
Постановка задачи
Рассмотрим фабрику декораторов, которая перемножает список чисел, выводит результат, а затем вызывает обёрнутую функцию. Структура верная, но если вы только знакомитесь с фабриками, место для @wraps может быть неочевидным.
from functools import wraps
def product_chain(values):
def apply_to(func_obj):
def inner_exec(*args, **kwargs):
acc = values[0]
for nxt in values[1:]:
acc = acc * nxt
print(acc)
return func_obj(*args)
return inner_exec
return apply_to
@product_chain(values=[1, 2, 3])
def announce(**kwargs):
print("That was the multiplied number.")
announce()
Что здесь происходит
@wraps сам по себе является декоратором. Его импортируют из functools и ставят непосредственно над внутренней функцией-обёрткой. Хотя в документации это чаще показывают на примере обычного декоратора, при фабрике действует тот же принцип: вы всё равно декорируете именно обёртку, которую возвращаете.
Исправление
Импортируйте wraps из functools и примените его к функции-обёртке внутри фабрики, передав ей исходную функцию.
from functools import wraps
def product_chain(values):
def apply_to(func_obj):
@wraps(func_obj)
def inner_exec(*args, **kwargs):
acc = values[0]
for nxt in values[1:]:
acc = acc * nxt
print(acc)
return func_obj(*args)
return inner_exec
return apply_to
@product_chain(values=[1, 2, 3])
def announce(**kwargs):
print("That was the multiplied number.")
announce()
Почему расположение важно
Применение @wraps к функции-обёртке в фабрике декораторов совпадает с практикой для обычных декораторов и снимает вопрос «какую именно функцию декорировать». Такой подход соответствует официальным рекомендациям и ведёт себя одинаково в обоих случаях.
Вывод
Работая с фабрикой декораторов, импортируйте wraps из functools и применяйте его к внутренней обёртке, которую возвращаете. Размещайте @wraps(original_function) прямо над определением обёртки. Этот шаблон такой же, как и в обычных декораторах, и делает использование ясным и предсказуемым.