Перейти к основному содержимому

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

С помощью декоратора можно дать функции дополнительное поведение, не трогая её код.

Декоратор сам является функцией. Он принимает функцию на вход и возвращает новую.


Простой декоратор

Сначала определите декоратор, а затем напишите @decorator_name в строке над функцией, к которой хотите его применить.

В этом примере строка @changecase прямо над myfunction «декорирует» её с помощью changecase.

Значит, changecase — это декоратор.

А myfunction — это функция, которую декорируют.

Пример

Этот декоратор переводит в верхний регистр всё, что возвращает декорированная функция.

Prompt
Создайте декоратор changecase, который переводит возвращаемое значение функции в верхний регистр. Примените его к функции, которая возвращает "Hello Sally", и выведите результат.
Вывод: полная программа на Python

Многократное использование декоратора

Один декоратор можно использовать сколько угодно раз. Просто поместите его над каждой функцией, которой он нужен.

Пример

Один и тот же декоратор @changecase, применённый к двум функциям:

Prompt
Создайте декоратор changecase, который переводит возвращаемые значения в верхний регистр. Примените его к двум разным функциям и выведите оба результата.
Вывод: полная программа на Python

Аргументы декорированной функции

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

Пример

Декорирование функции, которая принимает аргумент:

Prompt
Создайте декоратор changecase, который работает с функцией, принимающей один аргумент. Декорированная функция должна возвращать приветствие в верхнем регистре.
Вывод: полная программа на Python

*args и **kwargs

Декоратор не всегда может знать, какие аргументы получит декорированная функция. Решение — дать функции-обёртке параметры (*args, **kwargs). Тогда она сможет принимать любое количество аргументов любого типа и передавать их декорированной функции.

Пример

Делаем обёртку безопасной с помощью *args и **kwargs:

Prompt
Создайте декоратор changecase, использующий *args и **kwargs для гибкости. Примените его к функции, которая принимает параметр с именем.
Вывод: полная программа на Python

Декоратор с аргументами

Чтобы дать декоратору собственные аргументы, оберните его ещё в один уровень функции.

Пример

Фабрика декораторов: полученный аргумент определяет, в каком регистре будет результат.

Prompt
Создайте фабрику декораторов changecase, которая принимает аргумент n. Если n==1, переведите результат в нижний регистр; иначе — в верхний.
Вывод: полная программа на Python

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

У одной функции может быть несколько декораторов.

Просто разместите вызовы декораторов один над другим.

Они применяются в обратном порядке: первым идёт декоратор, ближайший к функции.

Пример

Один декоратор добавляет приветствие, а другой переводит текст в верхний регистр:

Prompt
Создайте два декоратора: changecase (верхний регистр) и addgreeting (добавляет текст приветствия). Примените оба к одной функции и выведите результат.
Вывод: полная программа на Python

Сохранение метаданных функции

У каждой функции в Python есть метаданные, которые можно прочитать через её атрибуты __name__ и __doc__.

Но при декорировании функции эти метаданные теряются, и исходные значения становятся недоступны.

В стандартной библиотеке есть решение: функция functools.wraps сохраняет имя и строку документации (docstring) исходной функции.

Пример

Функция без декоратора сообщает своё имя через __name__:

Prompt
Покажите, как получить имя функции с помощью атрибута __name__.
Вывод: полная программа на Python

Пример

Спросите у декорированной функции её имя, и ответ будет другим:

Prompt
Покажите, что декорированная функция теряет своё исходное __name__. Выведите __name__ декорированной функции.
Вывод: полная программа на Python

Пример

Если импортировать и применить functools.wraps, исходные имя и строка документации сохраняются.

Prompt
Используйте functools.wraps, чтобы сохранить исходное имя функции при декорировании. Выведите __name__ декорированной функции.
Вывод: полная программа на Python