You are currently viewing Как сохранить метаданные функций при использовании декораторов?

Как сохранить метаданные функций при использовании декораторов?

Декораторы-очень мощный и полезный инструмент в Python, поскольку он позволяет программистам изменять поведение функции или класса. Декораторы позволяют нам обернуть другую функцию, чтобы расширить поведение обернутой функции без ее постоянного изменения.
Примечание: Для получения дополнительной информации обратитесь к декораторам в Python

Как сохранить метаданные?

Это можно сделать с помощью метода wraps() функций. Он обновляет функцию-оболочку, чтобы она выглядела как обернутая функция, копируя такие атрибуты, как __name__, __doc__ (строка документа) и т. д.

Пример:

import time
from functools import wraps


def timethis(func):
	'''Decorator that reports the execution time.'''
	
	@wraps(func)
	def wrapper(*args, **kwargs):
		start = time.time()
		result = func(*args, **kwargs)
		end = time.time()
		
		print(func.__name__, end-start)
		return result
	
	return wrapper

@timethis
def countdown(n:int):
	'''Counts down'''
	while n > 0:
		n -= 1
		
countdown(100000)
print(countdown.__name__)
print(countdown.__doc__)
print(countdown.__annotations__)

Выход:

countdown 0.00827932357788086
countdown
Counts down
{'n': <class 'int'>}

Преимущества использования wraps():

  • Копирование метаданных декоратора является важной частью написания декораторов. Если вы забудете использовать @wraps, вы обнаружите, что украшенная функция теряет все виды полезной информации. Например, если этот параметр опущен, вывод последнего примера будет выглядеть следующим образом:
countdown 0.030733823776245117
wrapper
None
{}
  • Важной особенностью декоратора @wraps является то, что он делает функцию wrapped доступной для вас в атрибуте __wrapped__. Например, если вы хотите получить прямой доступ к обернутой функции, вы можете сделать это:
countdown.__wrapped__(100000)
  • Наличие атрибута __wrapped__ также позволяет оформленным функциям правильно отображать базовую сигнатуру обернутой функции. Например:
from inspect import signature

print(signature(countdown))

Выход:

(n:int)