Декораторы в python

Иногда нужно модифицировать существующую функцию, не меняя при этом ее исходный код. Чаще всего добавляется выражение для отладки, чтобы посмотреть, какие аргументы были переданы.
Декоратор - это функция, которая принимает одну функцию в качестве аргумента и возвращает другую функцию.

>>> def document_it(func):
		def new_function(*args, **kwargs):
			print('Running function:', func.__name__)
			print('Positional arguments:', args)
			print('Keyword arguments:', kwargs)
			result = func(*args, **kwargs)
			print('Result:', result)
			return result
		return new_function

Функция document_it() определяет декоратор, который:

  • выведет имя функции и значения переданных в нее аргументов
  • запустит функцию с полученными аргументами
  • выведет результат
  • вернет модифицированную функцию, готовую для использования

Передав любую функцию (func) в document_it(), вернется новая функция с доп. выражениями, которые добавил document_it(). Декоратор не обязательно должен запускать код функции func, но функция document_it() вызовет часть func, чтобы вернуть результат работы функции func, а также доп. данные:

>>> def add_ints(a, b):
		return a + b
 
>>> add_ints(3, 5)
8
 
>>> cooler_add_ints = document_it(add_ints)
>>> cooler_add_ints(3, 5)
Running function: add_ints
Positional arguments: (3, 5)
Keyword arguments: {}
Result: 8
8

Как альтернатива созданию декоратора вручную (👆) можно просто добавить конструкцию @имя_декоратора перед функцией, которую нужно декорировать:

>>> @document_it
	def add_ints(a, b):
		return a + b
 
>>> add_ints(3, 5)
Running function add_ints
Positional arguments: (3, 5)
Keyword arguments: {}
Result: 8
8

Несколько декораторов

У каждой функции может быть больше одного декоратора:

>>> def square_it(func):  # декоратор
		def new_function(*args, **kwargs):
			result = func(*args, **kwargs)
			return result * result
		return new_function

Декоратор, который ближе всего к функции (над def), будет выполняться первым и так наверх. Пример с двумя декораторами (с изменением их порядка для демонстрации):

>>> @square_it
	@document_it
	 def add_ints(a, b):
		return a + b
 
>>> add_ints(3, 5)
Running function: add_ints
Positional arguments: (3, 5)
Keyword arguments: {}
Result: 8
64
 
>>> @document_it
	@square_it
	 def add_ints(a, b):
		return a + b
 
>>> add_ints(3, 5)
Running function: new_function
Positional arguments: (3, 5)
Keyword arguments: {}
Result: 64
64

Функции в python
Соус: Книга “Простой Python Глава 9. “ФункцииДекоратор

python