Декораторы в Python: примеры использования

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

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

Ниже давайте рассмотрим различные примеры использования декораторов.

Декораторы в Python: примеры использования

Пример 1

Давайте начнем разбирать действие декораторов на примерах. Возьмём декоратор с именем decorator1 и внутренний класс new_func. Обе эти функции содержат аргументы. Далее мы подробно рассмотрим функциональность декоратора с аргументами.

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

python decorator examples 01

Пример 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 печатается позже. Это из-за порядка вызова функций с аргументами.

python decorator examples 03

Создание цепочки декораторов

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

Сначала определяем оба декоратора, со звездочками и плюсами. Затем оба декоратора прикрепляются к функции 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 decorator examples 06

Заключение

Сегодня мы рассмотрели декораторы в Python и несколько примеров их использования. Надеемся, это помогло вам понять базовую концепцию работы декораторов в Python.