Декораторы в Python — это способ изменять поведение функции или класса без правки их исходного кода. Если вы встречали @staticmethod, @classmethod или @login_required, значит уже работали с декораторами.
Почему тема важна:
- помогают переиспользовать код
- убирают дублирование
- удобны для логирования, кэширования, проверки прав доступа, замера времени выполнения
Что такое декоратор
По сути, декоратор — это функция, которая принимает другую функцию и возвращает новую.
Простой пример:
def decorator(func):
def wrapper():
print("До вызова функции")
func()
print("После вызова функции")
return wrapper
@decorator
def hello():
print("Привет!")
hello()
Это аналогично записи:
hello = decorator(hello)
Как это работает
Когда Python видит @decorator, он:
- берет функцию hello
- передает ее в decorator
- сохраняет результат обратно в hello
То есть вызывается уже не исходная функция, а обертка wrapper.
Декораторы с аргументами
Если функция принимает параметры, обертка тоже должна их принимать:
def decorator(func):
def wrapper(*args, **kwargs):
print("Запуск функции")
result = func(*args, **kwargs)
print("Функция завершена")
return result
return wrapper
*args и **kwargs делают декоратор универсальным — это стандартная практика. ✅
Важный момент: metadata функции
Без дополнительных действий декоратор “ломает” имя и docstring исходной функции. Для этого используют functools.wraps:
from functools import wraps
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
Это особенно важно в больших проектах, тестах и фреймворках.
Декораторы с параметрами
Иногда нужно передать настройки в сам декоратор. Тогда появляется еще один уровень вложенности:
from functools import wraps
def repeat(n):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
for _ in range(n):
func(*args, **kwargs)
return wrapper
return decorator
@repeat(3)
def greet():
print("Hi")
Здесь repeat(3) сначала создает декоратор, а уже потом он оборачивает функцию.
Где применяются на практике
- Логирование — фиксировать вызовы функций
- Кэширование — например, через @lru_cache 🚀
- Авторизация — проверка доступа пользователя
- Измерение времени — профилирование медленных участков
- Повторные попытки — retry при сетевых ошибках
Частые ошибки
- забывают return result
- не используют wraps
- пишут декоратор без *args, **kwargs, из-за чего он работает только для одной сигнатуры
- слишком усложняют логику, превращая код в “матрешку” 🤯
Итог
Декораторы — это не “магия Python”, а удобный инструмент для расширения поведения кода. Начинать стоит с простых оберток, затем переходить к параметризованным декораторам и встроенным решениям вроде @wraps и @lru_cache. Понимание декораторов особенно важно для backend-разработки, автоматизации и работы с фреймворками Django/FastAPI. 🔧💡
📌 Ниже стоит посмотреть подборку каналов про IT — там много полезного по Python, backend и разработке в целом.