Ответ
Декоратор @functools.wraps
используется для того, чтобы функция-обертка, создаваемая декоратором, наследовала метаданные (имя, docstring, аннотации типов, аргументы) от исходной декорируемой функции.
Проблема, которую он решает:
Без @wraps
метаданные оригинальной функции заменяются метаданными функции-обертки. Это затрудняет отладку (например, в стектрейсах отображается имя wrapper
), а также нарушает работу инструментов для интроспекции и автоматической генерации документации.
Пример без @wraps
:
def my_decorator(func):
def wrapper(*args, **kwargs):
"""Это документация обертки."""
print("Что-то до вызова функции.")
return func(*args, **kwargs)
return wrapper
@my_decorator
def say_hello():
"""Это документация оригинальной функции."""
print("Привет!")
print(say_hello.__name__) # Выведет: 'wrapper'
print(say_hello.__doc__) # Выведет: 'Это документация обертки.'
Пример с @wraps
:
from functools import wraps
def my_decorator(func):
@wraps(func) # Копируем метаданные из func в wrapper
def wrapper(*args, **kwargs):
"""Это документация обертки (игнорируется благодаря @wraps)."""
print("Что-то до вызова функции.")
return func(*args, **kwargs)
return wrapper
@my_decorator
def say_hello():
"""Это документация оригинальной функции."""
print("Привет!")
print(say_hello.__name__) # Выведет: 'say_hello'
print(say_hello.__doc__) # Выведет: 'Это документация оригинальной функции.'