Декоратор – это функция, которая оборачивает другую функцию, расширяя её функциональность без изменения исходного кода. По сути, это обертка, изменяющая поведение декорируемой функции.
Декораторы как объекты
В 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, позволяющий улучшать читаемость и поддерживаемость кода, избегая дублирования. Они особенно полезны для расширения функциональности без изменения исходного кода функций. Хотя освоение декораторов требует усилий, их использование значительно упрощает работу с более сложными задачами.