Каково назначение декоратора functools.wraps в Python?

Ответ

Декоратор @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__)   # Выведет: 'Это документация оригинальной функции.'