Python Декораторы функций: Урок 19 (с нуля)

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

Декораторы как объекты

В Python всё является объектом, включая функции. Это позволяет проводить с функциями различные манипуляции: возвращать их как значения, передавать в качестве аргументов и т.д. Рассмотрим создание простого декоратора.

Создание простого декоратора

Создадим функцию-декоратор декор, которая принимает другую функцию в качестве аргумента:

def декор(func):
    def обёртка():
        print("Старт")
        func()
        print("End")
    return обёртка

Внутри декор определена вложенная функция обёртка. Она выводит сообщение «Старт», затем вызывает переданную функцию func, и наконец, выводит сообщение «End». Декоратор возвращает функцию обёртка.

Теперь создадим простую функцию:

def моя_функция():
    print("Тут основная функция")

Применение декоратора

Существует два способа применения декоратора:

Способ 1: Присваивание переменной:

моя = декор(моя_функция)
моя()

Здесь переменная моя получает значение, возвращаемое декоратором – функцию обёртка. Вызов моя() выполняет код обёртки, тем самым декорируя моя_функция.

Способ 2: Использование декоратора как синтаксического сахара (более распространенный):

@декор
def моя_функция():
    print("Тут основная функция")

моя_функция()

Этот способ эквивалентен первому, но более компактен и читаем.

Зачем нужны декораторы?

Декораторы позволяют:

  • Избегать повторения кода.
  • Расширять функциональность функций без изменения их исходного кода.

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

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

Рассмотрим случай, когда функция принимает аргументы. Изменим моя_функция и обёртка:

def моя_функция(n):
    return n**2

def декор(func):
    def обёртка(n):
        print("Старт")
        result = func(n)
        print("End")
        return result
    return обёртка

@декор
def моя_функция(n):
    return n**2

print(моя_функция(10))

Важно передать аргументы n в обёртку, иначе возникнет ошибка. Теперь результат вычислений возвращается корректно.

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

Если функция декорируется несколькими декораторами, они применяются в обратном порядке их объявления.

Практический пример: измерение времени выполнения функции

Создадим декоратор для измерения времени выполнения функции:

import time

def май_декор(func):
    def обёртка(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f"Время выполнения: {end_time - start_time:.4f} секунд")
        return result
    return обёртка

@май_декор
def sp():
    pass

sp()

Этот декоратор измеряет время выполнения функции и выводит результат. Можно использовать его для профилирования кода.

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

Что будем искать? Например,программа