Декораторы в Python
Сегодня мы рассмотрим одну из самых мощных и элегантных возможностей Python — декораторы. Они позволяют модифицировать или расширять функции и методы без изменения их исходного кода! Представьте декораторы как специальные обертки, добавляющие дополнительную функциональность вашему коду. 🎁
Что такое декораторы?
Декоратор — это особый вид функции, которая принимает другую функцию в качестве входных данных, расширяет или изменяет ее поведение и возвращает измененную функцию без изменения ее исходного кода.
Декораторы следуют ключевому принципу в программировании — Принципу открытости/закрытости, который гласит, что код должен быть открыт для расширения, но закрыт для модификации. С помощью декораторов вы можете добавлять новое поведение функциям без изменения их оригинального кода.
Базовый синтаксис декораторов
Базовый синтаксис использования декоратора очень прост — вы размещаете строку @имя_декоратора прямо над определением функции:
>>> def my_decorator(func): ... def wrapper(): ... print("Что-то происходит до вызова функции") ... func() # Вызов оригинальной функции ... print("Что-то происходит после вызова функции") ... return wrapper >>> @my_decorator >>> def say_hello(): ... print("Привет, мир!") # Вызов декорированной функции >>> say_hello()
Что-то происходит до вызова функцииПривет, мир!Что-то происходит после вызова функции
Это эквивалентно:
>>> def my_decorator(func): ... def wrapper(): ... print("Что-то происходит до вызова функции") ... func() ... print("Что-то происходит после вызова функции") ... return wrapper >>> def say_hello(): ... print("Привет, мир!") # Декорирование функции вручную >>> decorated_hello = my_decorator(say_hello) # Вызов декорированной функции >>> decorated_hello()
Что-то происходит до вызова функцииПривет, мир!Что-то происходит после вызова функции
Декораторы с аргументами
Что если функция, которую вы декорируете, принимает аргументы? Вам нужно сделать вашу функцию-обертку способной принимать и передавать эти аргументы:
>>> def my_decorator(func): ... def wrapper(*args, **kwargs): ... print("Что-то происходит до вызова функции") ... # Вызов оригинальной функции со всеми аргументами ... result = func(*args, **kwargs) ... print("Что-то происходит после вызова функции") ... return result ... return wrapper >>> @my_decorator >>> def add(a, b): ... return a + b # Вызов декорированной функции с аргументами >>> result = add(5, 3) >>> print(f"Результат: {result}")
Что-то происходит до вызова функцииЧто-то происходит после вызова функцииРезультат: 8
Синтаксис *args и **kwargs позволяет обертке принимать любое количество позиционных и именованных аргументов, делая ее гибкой и работающей с любой функцией.
Практические примеры декораторов
Давайте рассмотрим практический пример декоратора, чтобы увидеть, насколько они могут быть полезны в реальном коде.
Замер времени выполнения функций
Декоратор для измерения времени выполнения функции:
>>> import time >>> def timing_decorator(func): ... def wrapper(*args, **kwargs): ... start_time = time.time() ... result = func(*args, **kwargs) ... end_time = time.time() ... execution_time = end_time - start_time ... print(f"Функция {func.__name__} выполнялась {execution_time:.4f} секунд") ... return result ... return wrapper >>> @timing_decorator >>> def calculate_sum(n): ... return sum(range(n)) >>> calculate_sum(1000000)
Функция calculate_sum выполнялась 0.0462 секунд
Декораторы с параметрами
Иногда вам нужны декораторы, которые могут принимать собственные параметры. Это требует добавления еще одного уровня вложенности:
>>> def repeat(n=1): ... def decorator(func): ... def wrapper(*args, **kwargs): ... result = None ... for _ in range(n): ... result = func(*args, **kwargs) ... return result ... return wrapper ... return decorator >>> @repeat(n=3) >>> def say_hi(name): ... print(f"Привет, {name}!") ... return "Готово" >>> say_hi("Алиса")
Привет, Алиса!Привет, Алиса!Привет, Алиса!
В этом примере у нас есть три уровня функций:
- repeat(n) — принимает параметр декоратора
- decorator(func) — принимает функцию для декорирования
- wrapper(*args, **kwargs) — обрабатывает вызов функции
Цепочка декораторов
Вы можете применить несколько декораторов к одной функции. Они выполняются снизу вверх (декоратор, находящийся ближе всего к функции, применяется первым):
>>> def bold(func): ... def wrapper(*args, **kwargs): ... return f"<b>{func(*args, **kwargs)}</b>" ... return wrapper >>> def italic(func): ... def wrapper(*args, **kwargs): ... return f"<i>{func(*args, **kwargs)}</i>" ... return wrapper >>> @bold >>> @italic >>> def format_text(text): ... return text >>> print(format_text("Привет, мир!"))
<b><i>Привет, мир!</i></b>
Декораторы классов
Помимо декорирования функций, вы также можете создавать декораторы для классов:
>>> def add_greeting(cls): ... # Добавление нового метода к классу ... cls.greet = lambda self: f"Привет от {self.__class__.__name__}" ... return cls >>> @add_greeting >>> class Person: ... def __init__(self, name): ... self.name = name # Создание экземпляра и использование добавленного метода >>> person = Person("Алиса") >>> print(person.greet())
Привет от Person
Реальные примеры использования декораторов
Декораторы широко используются в Python и во многих популярных фреймворках:
-
Маршрутизация во Flask/Django — сопоставление URL с функциями представления
@app.route('/home') def home(): return "Добро пожаловать на домашнюю страницу!"
-
Декораторы свойств — контроль доступа к атрибутам
class Person: def __init__(self, name): self._name = name @property def name(self): return self._name @name.setter def name(self, value): if not value: raise ValueError("Имя не может быть пустым") self._name = value
-
Мемоизация/кэширование — сохранение результатов функции для избежания повторных вычислений
def memoize(func): cache = {} def wrapper(*args): if args not in cache: cache[args] = func(*args) return cache[args] return wrapper
-
Ограничение частоты — ограничение частоты вызова функции
-
Валидация — проверка входных данных перед обработкой
-
Авторизация — проверка разрешений перед выполнением функций
Проверка понимания
В чем основное назначение декораторов в Python?
Заключение
Декораторы — это мощная функция в Python, которая позволяет элегантно организовывать и повторно использовать код. Они помогают реализовать сквозные задачи, такие как логирование, аутентификация и мониторинг производительности, не загромождая реальную бизнес-логику ваших функций.
По мере продолжения вашего пути в Python, вы обнаружите, что декораторы являются важным инструментом для написания чистого, поддерживаемого и расширяемого кода. Они особенно распространены в фреймворках и библиотеках Python, поэтому понимание их работы сделает вас более эффективным в использовании этих инструментов.