Сегодня мы поговорим о такой особенности языка Python как декораторы. Декораторы – это специально созданные функции, которые помогают добавить дополнительную функциональность в уже существующий код. Интересен тот факт, что в других языках (например, в С) подобных штук нет.
Декоратор меняет поведение других функций. При этом он не прерывает работу основной функции. Декораторы в Python могут быть как функциями, так и классами. Обычно декораторы вызываются перед определением функции, которую нужно декорировать.
Ниже давайте рассмотрим различные примеры использования декораторов.
Декораторы в Python: примеры использования
Пример 1
Давайте начнем разбирать действие декораторов на примерах. Возьмём декоратор с именем decorator1
и внутренний класс new_func
. Обе эти функции содержат аргументы. Далее мы подробно рассмотрим функциональность декоратора с аргументами.
В этом примере мы добавляем символ доллара с номером, который указываем в конце вызова функции. Это вызов декорированной функции. myfunction
используется, чтобы просто вернуть полученный аргумент. Исходный код приведен ниже. Выходные данные показывают, что символ $ и число объединены.
Пример 2
Разберем следующий пример. Есть два декоратора. Сначала определим decorator1
, а затем wrapper
как его внутреннюю функцию (англ. wrapper — обертка).
Во wrapper у нас сначала идет вывод первого сообщения (first message), затем функция, которая собственно и оборачивается в обертку при помощи декоратора, а затем — вывод второго сообщения (second message).
В конце функции decorator1
возвращается внутренняя функция wrapper
.
Далее определим второй декоратор — decorator2
. Эта функция просто выводит третье сообщение (3rd message).
После этого «декорируем» decorator2, как показано в предпоследней строке кода. И, наконец, последней строчкой кода мы вызываем декорированную функцию.
def decorator1(function): def wrapper(): print('this is first message') function() print ('this is second message') return wrapper def decorator2(): print('this is 3rd message') decorator2 = decorator1(decorator2) decorator2()
В выводе сначала отображается первое сообщение. После этого выводится третье сообщение (вследствие вызова функции decorator2
). А второе сообщение отображается лишь в конце.
this is first message this is 3rd message this is second message
Возврат значений из декорированных функций
Следующий пример касается передачи или получения аргументов в декораторе. Это чем-то похоже на передачу значений в обычные функции.
У внутренней функции в нашем примере есть параметры. При передаче аргументов для возврата значения с этим трудно справиться. Чтобы свести к минимуму эту проблему, в функции-оболочке мы будем использовать *args
и **kwargs
.
Ниже мы видим результат — python
печатается первым, а Сoding is easy
печатается позже. Это из-за порядка вызова функций с аргументами.
Создание цепочки декораторов
Мы составили цепочку декораторов с помощью символов звездочки и плюса. В данном примере для декорирования функции используется более одного декоратора.
Сначала определяем оба декоратора, со звездочками и плюсами. Затем оба декоратора прикрепляются к функции function()
: они указываются над функцией, а перед ними ставится знак @. Таким образом функция модифицируется, а вывод будет декорированным.
def decorator1(f): def wrapped(): return '*****' + f() + '*****' return wrapped def decorator2(f): def wrapped(): return '+++' + f() + '+++' return wrapped @decorator1 @decorator2 def function(): return 'Python 3.8' print(function())
В обертках звездочки и плюсы добавлены до и после вызова функции. В результате с каждой стороны строки прикрепляется по 5 звездочек и 3 знака «плюс».
*****+++Python 3.8+++*****
Добавление нескольких декораторов к одной функции
Пропишем два декоратора. Первый — для разделения строки. Второй — для приведения к верхнему регистру. После этого, под вызовами, мы определим еще один декоратор, который разделит предложение и сделает его списком.
def decorator1(function): def wrapper(): func = function() splitted_string = func.split() return splitted_string return wrapper def decorator2uppercase(function): def wrapper(): func = function() make_uppercase = func.upper() return make_uppercase return wrapper @decorator1 @decorator2uppercase def say_hi(): return 'python is good language' print(say_hi())
В приведенном выше коде сначала все буквы предложения переводятся в верхний регистр, а затем предложение разбивается на части. Получившиеся слова возвращаются в виде списка. Обратите внимание, что изначально предложение было написано строчными буквами.
['PYTHON', 'IS', 'GOOD', 'LANGUAGE']
Использование декораторов Python при обработке исключений
Теперь давайте обработаем исключение, используя декоратор. В качестве примера взят массив. После определения декораторов мы использовали функцию, которая принимает новое значение или позицию массива. Конкретное назначение этой функции – проверить условие if pos >= len(array):
. Мы использовали здесь оператор if
, чтобы упростить задачу.
Эта строка является основой всей программы, так как проверяет ее работоспособность. Она проверяет, не превышает ли позиция массива размер массива, и в случае превышения выводит сообщение об ошибке. В противном случае функция будет выполнять действие декораторов.
В примере на скриншоте значение индекса больше размера массива. Следовательно, в выводе мы увидим сообщение об ошибке.
Заключение
Сегодня мы рассмотрели декораторы в Python и несколько примеров их использования. Надеемся, это помогло вам понять базовую концепцию работы декораторов в Python.