Зачем использовать wraps в декораторах

Возьмём простой декоратор для примера и создадим простую функцию с его использованием:

def decorator_name(f):
    def decorated_function(*args, **kwargs):
        print("Some code")
        return f(*args, **kwargs)
    return decorated_function

@decorator_name
def print_hi(name):
    print(f'Hi, {name}')

Выведем имя функции:

print(print_hi.__name__)
# --> decorated_function 

То есть мы получили название вложенной в декоратор функции, вместо той, о которой хотим получить данные. Но это ещё не всё. Если мы не используем wraps и пробуем получить строки документации, которые указаны непосредственно в нашей функции, то результат ничего не даст, т.к. будет идти поиск строк документации непосредственно в decorated_function, и помимо этого в pydoc будет указано, что функция принимает *args, **kwargs, проще говоря, мы будем получать данные о decorated_function, а не о нашей функции print_hi, находящейся под декоратором.

Теперь добавим wraps:

from functools import wraps


def decorator_name(f):
	@wraps(f)
    def decorated_function(*args, **kwargs):
        print("Some code")
        return f(*args, **kwargs)
    return decorated_function

@decorator_name
def print_hi(name):
    print(f'Hi, {name}')

И повторно выведем имя:

print(print_hi.__name__)
# --> print_hi 

Добавим строки документации в функцию print_hi:

@decorator_name
def print_hi(name):
    """Sample function.

    Args:
        name: your name.

    Returns:
        None
    """
    print(f'Hi, {name}')

Теперь, если использовать декоратор без wraps и вызвать __doc__ у функции print_hi, то мы получим None, т.к. на самом деле мы будем запрашивать строки документации по функции decorated_function, в которой ранее мы ничего не прописали:

def decorator_name(f):
    def decorated_function(*args, **kwargs):
        print("Some code")
        return f(*args, **kwargs)
    return decorated_function

print(print_hi.__doc__)  
# -> None

Если мы использовали wraps, то нам вернутся требуемые строки документации:

def decorator_name(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        print("Some code")
        return f(*args, **kwargs)
    return decorated_function

print(print_hi.__doc__)  
""" 
-> Sample function.

    Args:
        name: your name.

    Returns:
        None
"""

Таким образом functools.wraps позволяет скопировать данные по типу имени функции, строк документации, списка аргументов и т.п. в информацию о декорируемой функции.

0

Автор публикации

не в сети 1 месяц

art610

1000K
Lnovus Support
Комментарии: 0Публикации: 41Регистрация: 04-06-2022
Оцените материал
( Пока оценок нет )
Locus Novus
Добавить комментарий

Авторизация
*
*
Регистрация
*
*
*
Пароль не введен
Генерация пароля