Декораторы в Python: мощный инструмент для функций

Введение: 

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

Декораторы — это не просто синтаксический сахар. Они лежат в основе многих популярных библиотек и фреймворков: от кеширования в @lru_cache до маршрутизации в Flask (@app.route). Их сила — в способности добавлять новую логику чисто и декларативно, будь то:

  • Логирование вызовов функций

  • Замер времени выполнения

  • Контроль доступа (например, проверка авторизации)

  • Автоматический повтор запросов при ошибках

  • Кеширование результатов

В этом посте мы разберём:
✔️ Базовые декораторы — как они устроены под капотом
✔️ Продвинутые техники — параметризованные декораторы, wraps, работа с классами
✔️ Практические примеры — от таймеров до ретраев в API
✔️ Где это применяется в реальных проектах

1. Базовый декоратор

def logger(func):
def wrapper(*args, **kwargs):
print(f»Вызов функции {func.__name__}»)
return func(*args, **kwargs)
return wrapper

@logger
def greet(name):
return f»Привет, {name}!»

print(greet(«Мир»))

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

def repeat(n):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(n):
result = func(*args, **kwargs)
return result
return wrapper
return decorator

@repeat(3)
def say_hello():
print(«Hello!»)

say_hello()

3. Кеширование с functools.lru_cache

from functools import lru_cache

@lru_cache(maxsize=128)
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)

print(fibonacci(100))

4. Декоратор для замера времени

import time

def timer(func):
def wrapper(*args, **kwargs):
start = time.perf_counter()
result = func(*args, **kwargs)
end = time.perf_counter()
print(f»Время выполнения: {end — start:.4f} сек.»)
return result
return wrapper

@timer
def slow_function():
time.sleep(2)

slow_function()

5. Декораторы в классах

class Debugger:
def __init__(self, func):
self.func = func

def __call__(self, *args, **kwargs):
print(f»Отладка: {self.func.__name__}»)
return self.func(*args, **kwargs)

@Debugger
def multiply(a, b):
return a * b

print(multiply(5, 6))

6. Декораторы для проверки прав доступа

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

def login_required(func):
def wrapper(user, *args, **kwargs):
if not user.get(«is_authenticated»):
raise PermissionError(«Требуется авторизация»)
return func(user, *args, **kwargs)
return wrapper

@login_required
def view_profile(user):
return f»Профиль: {user[‘name’]}»

user = {«name»: «Alice», «is_authenticated»: True}
print(view_profile(user))

7. Декораторы с параметрами и functools.wraps

Чтобы сохранить исходные метаданные функции (например, __name____doc__), используют functools.wraps:

from functools import wraps

def deprecated(message):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(f»Внимание: {func.__name__} устарела. {message}»)
return func(*args, **kwargs)
return wrapper
return decorator

@deprecated(«Используйте новую функцию ‘calculate_v2′»)
def calculate(x, y):
«»»Возвращает сумму двух чисел.»»»
return x + y

print(calculate(2, 3))
print(calculate.__name__)
print(calculate.__doc__)

8. Декораторы для асинхронных функций

Декораторы также работают с async/await:

import asyncio

def async_timer(func):
async def wrapper(*args, **kwargs):
start = time.perf_counter()
result = await func(*args, **kwargs)
end = time.perf_counter()
print(f»Асинхронная функция выполнилась за {end — start:.2f} сек.»)
return result
return wrapper

@async_timer
async def fetch_data():
await asyncio.sleep(1)
return «Данные получены»

asyncio.run(fetch_data())

9. Несколько декораторов на одной функции

Декораторы применяются снизу вверх (ближайший к функции выполняется первым):

def bold(func):
def wrapper():
return f»<b>{func()}</b>»
return wrapper

def italic(func):
def wrapper():
return f»<i>{func()}</i>»
return wrapper

@bold
@italic
def hello():
return «Привет, мир!»

print(hello())

10. Декораторы в промышленной разработке

В реальных проектах декораторы часто используются для:

  • Валидации аргументов (@validate_input)

  • Ретри-логики (@retry_on_failure)

  • Транзакций БД (@transactional)

  • Лимитирования запросов (@rate_limit)

Пример декоратора для повторного выполнения функции при ошибке:

import random
from time import sleep

def retry(max_attempts=3, delay=1):
def decorator(func):
def wrapper(*args, **kwargs):
for attempt in range(max_attempts):
try:
return func(*args, **kwargs)
except Exception as e:
if attempt == max_attempts — 1:
raise
sleep(delay)
return wrapper
return decorator

@retry(max_attempts=5)
def unstable_operation():
if random.random() < 0.7:
raise ValueError(«Ошибка!»)
return «Успех»

print(unstable_operation())

Заключение: 

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

✅ Уменьшить дублирование — выносим общую логику в декораторы
✅ Делать код читаемее — функциональность становится декларативной
✅ Легко масштабировать — новые возможности добавляются без изменения исходного кода
✅ Следовать принципам SOLID — особенно принципу открытости/закрытости
✅ Использовать лучшие практики — кеширование, логирование, обработка ошибок

Главная сила декораторов — в их универсальности. Они одинаково полезны как в небольших скриптах, так и в крупных проектах, где важны чистая архитектура и производительность.

Для Дальнейшего Изучения

  1. Встроенные декораторы Python — углублённое изучение @property@classmethod@staticmethod

  2. Декораторы с сохранением состояния — как использовать замыкания и классы для более сложной логики

  3. Декораторы в популярных фреймворках — @app.route во Flask, @login_required в Django

  4. Метапрограммирование — как создавать декораторы, которые принимают другие декораторы

  5. Оптимизация производительности — @lru_cache@numba.jit и их аналоги

  6. Асинхронные декораторы — работа с async/await и конкурентным выполнением

  7. Тестирование декораторов — как правильно писать unit-тесты для сложных декораторов