Понимание декораторов Python с примерами

проекты Python Программирование и разработка

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

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

Концепция декораторов в Python помогает сохранить ваш код СУХИМ. Декоратор функций позволяет избежать ненужного повторения в кодовой базе, потому что некоторые повторяющиеся фрагменты кода можно объединить, чтобы они стали декораторами функций. По мере того, как вы продвигаетесь в использовании Python для разработки, декораторы могут помочь с аналитикой и ведением журнала. Они также необходимы для настройки валидации и проверок во время выполнения.

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

Что нужно понять, прежде чем углубляться в декораторы Python

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

Функция — это объект, а значит, ее можно присвоить другой переменной.

def greet():
    print("Hello John")
    
greet_john = greet
greet_john()
>>>
Hello John

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

Читайте также:  Функции C++ — передача по ссылке

Функция может быть возвращена из другой функции

def greet():
    def greeting_at_dawn():
        print("Good morning")
        
    return greeting_at_dawn

salute = greet()
salute()
>>>
Good morning

Внутренняя функция в Python может быть возвращена из внешней функции. Это часть концепции функционального программирования, с которой вы столкнетесь.

Функция может быть передана в качестве аргумента другой функции

def greet_some(func):
    print("Good morning", end=' ')
    func()

def say_name():
    print("John")

greet(say_name)
>>>
Good morning John

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

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

Как работают декораторы Python

Простая функция-декоратор начинается с определения функции, функции-декоратора, а затем вложенной функции во внешней функции-оболочке.

Всегда помните об этих двух основных моментах при определении декораторов:

  1. Чтобы реализовать декораторы, определите внешнюю функцию, которая принимает аргумент функции.
  2. Вложите функцию-оболочку во внешнюю функцию декоратора, которая также является оболочкой декорированной функции.

Вот как выглядит основная функция декоратора в приведенном ниже фрагменте кода:

def increase_number(func):
    def increase_by_one():
        print("incrementing number by 1 ...")
        number_plus_one = func()  + 1
        return number_plus_one
    return increase_by_one 
    
def get_number():
    return 5
    
get_new_number = increase_number(get_number)
print(get_new_number())
>>>
incrementing number by 1 ...
6

Глядя на приведенный выше код, внешняя функция, increase_numberтакже известная как декоратор, получает аргумент функции func. increase_by_oneэто функция-оболочка, в которой находится украшенная get_numberфункция. Декоратор назначается другой переменной. Вот как выглядит синтаксис декоратора при использовании декораторов Python. Однако есть гораздо более простой способ представления декораторов.

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

def increase_number(func):
    def increase_by_one():
        print("incrementing number by 1 ...")
        number_plus_one = func()  + 1
        return number_plus_one
    return increase_by_one 
    
@increase_number    
def get_number():
    return 5

print(get_number())
>>>
incrementing number by 1 ...
6

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

Функции декоратора с параметрами

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

def multiply_numbers(func):
    def multiply_two_numbers(num1, num2):
        print("we're multiplying two number {} and {}".format(num1, num2))
        return func(num1, num2)
        
    return multiply_two_numbers

@multiply_numbers
def multiply_two_given_numbers(num1, num2):
    return f'{num1} * {num2} = {num1 * num2}'
    
print(multiply_two_given_numbers(3, 4))
 >>>
we're multiplying two number 3 and 4
3 * 4 = 12

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

def decorator_func(decorated_func):
    def wrapper_func(*args, **kwargs):
        print(f'there are {len(args)} positional arguments and {len(kwargs)} keyword arguments')
        return decorated_func(*args, **kwargs)
        
    return wrapper_func

@decorator_func
def names_and_age(age1, age2, name1='Ben', name2='Harry'):
    return f'{name1} is {age1} yrs old and {name2} is {age2} yrs old'
    
print(names_and_age(12, 15, name1="Lily", name2="Ola"))
>>>
There are 2 positional arguments and 2 keyword arguments
Lily is 12 yrs old and Ola is 15 yrs old

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

Несколько декораторов или цепочка декораторов в Python

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

def increase_decorator(func):
    def increase_by_two():
        print('Increasing number by 2')
        new_number = func()
        return new_number + 2
        
    return increase_by_two
    

def decrease_decorator(func):
    def decrease_by_one():
        print('Decreasing number by 1')
        new_number = func()
        return new_number - 1
        
    return decrease_by_one
    
@increase_decorator
@decrease_decorator
def get_number():
    return 5
    
print(get_number())
>>> 
Increasing number by 2
Decreasing number by 1
6

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

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

Мемоизация — еще один классный способ использования декораторов в Python. Результаты вызовов функций, которые повторяются без каких-либо изменений, можно легко запомнить при последующих вычислениях. Вы можете просто запомнить функцию с помощью декораторов.

Встроенные декораторы Python, такие как @classmethod(метод класса), @staticmethod(статический метод) и @propertyочень популярны в шаблоне декоратора ООП Python.

Заключение

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

Декораторы упрощают добавление дополнительных функций к простой функции, методу или классу без необходимости изменять исходный код, сохраняя при этом ваш код СУХИМ. Попробуйте декорировать функции самостоятельно, чтобы лучше понять шаблон декоратора.

Оцените статью
bestprogrammer.ru
Добавить комментарий