Шаг 47.
Python: тонкости программирования. Эффективные функции. Сила декораторов. Применение многочисленных декораторов к функции

    На этом шаге мы рассмотрим использование нескольких декораторов к одной функции.

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

    Приведем пример. Представленные ниже два декоратора обертывают выходную строку декорированной функции в HTML-теги. Глядя на то, как теги

>>> def strong(func):
	def wrapper():
		return '<strong>' + func() + '</strong>'
	return wrapper

>>> def emphasis(func):
	def wrapper():
		return '<em>' + func() + '</em>'
	return wrapper

    Теперь давайте возьмем эти два декоратора и одновременно применим их к нашей функции greet(). Для этого вы можете использовать обычный синтаксис @ и просто "уложить" многочисленные декораторы вертикально поверх одной-единственной функции:

>>> @strong
@emphasis
def greet():
	return 'Привет!'

    Какой результат вы ожидаете увидеть, если выполнить декорированную функцию? Сначала декоратор @emphasis добавит тег <em>? Или же приоритет имеет тег @strong? Когда вы вызываете декорированную функцию, происходит вот что:

>>> greet()
'<strong><em>Привет!</em></strong>'

    Этот результат ясно показывает, в каком порядке декораторы были применены: снизу вверх. Сначала входная функция была обернута декоратором @emphasis, и затем результирующая (декорированная) функция снова была обернута декоратором @strong.

    Чтобы помочь себе запомнить порядок следования снизу-вверх, будем называть такое поведение стековой укладкой декораторов. Стек начинают строить снизу и затем продолжают добавлять новые блоки поверх старых, поднимаясь все выше и выше.

    Если разложить приведенный выше пример и избавиться от синтаксиса @, который применяют декораторы, то цепочка вызовов функций-декораторов выглядит так:

decorated_greet = strong(emphasis(greet))

    И снова вы видите, что сначала применяется декоратор emphasis() и затем результирующая обернутая функция снова обертывается декоратором strong().

    Это также означает, что глубокие уровни стековой укладки декораторов в конечном счете скажутся на производительности, потому что они будут добавлять все новые вызовы вложенных функций. На практике в этом нет проблем, но имейте это в виду, если работаете над вычислительно емким программным кодом, в котором декорирование применяется часто.

    На следующем шаге мы рассмотрим декорирование функций, принимающих аргументы.




Предыдущий шаг Содержание Следующий шаг