Короткий ответ
functools.wraps — декоратор из стандартного модуля functools, который применяется к функции-обёртке внутри декоратора. Он копирует обёртке метаданные декорируемой функции, чтобы она сохраняла её имя, документацию и другие атрибуты.
Как это работает подробнее
- Проблема. Без
wrapsобёртка затирает метаданные: имя функции становитсяwrapper, пропадают__doc__,__module__и другие атрибуты. - Последствия. В стектрейсах и ошибках фигурирует внутренняя обёртка вместо реальной функции, что ломает интроспекцию, документаторы и инструменты.
- Решение.
@wraps(func)копирует обёртке атрибуты декорируемой функции и обновляет её словарь__dict__, поэтому обёртка «выдаёт себя» за исходную функцию. - Правило. Хорошим тоном считается всегда оборачивать
wrapperв@wraps(func)при написании собственных декораторов.
Пример кода
Декоратор logged с сохранением метаданных
from functools import wraps
def logged(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(f'Вызов {func.__name__}')
return func(*args, **kwargs)
return wrapper
@logged
def add(a, b):
"""Складывает два числа."""
return a + b
print(add.__name__) # 'add', а не 'wrapper'
print(add.__doc__) # 'Складывает два числа.'Что использовать на практике
- Каждый декоратор. Применяй
@wraps(func)к обёртке во всех собственных декораторах — это просто и безопасно. - Отладка. Сохранённые
__name__и__doc__делают стектрейсы, логи и справку читаемыми. - Интроспекция. Документаторы и профилировщики корректно работают, когда метаданные функций не потеряны.
Подводные камни
- Забытый wraps. Без него
add.__name__вернётwrapper, а не имя реальной функции. - Не тот объект. Оборачивать нужно именно возвращаемую обёртку, а не декорируемую функцию.
- Забытый импорт. Не забудь импортировать
wrapsизfunctools, иначе код декоратора не выполнится.
Как отвечать на собеседовании
- Объясни проблему: без
wrapsобёртка затирает имя, docstring и другие метаданные → покажи пример декоратораloggedс@wraps(func)→ продемонстрируй, чтоadd.__name__иadd.__doc__сохраняются → сформулируй правило всегда использоватьwraps.