Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Примеры декораторов в Python
Декораторы — это функции высшего порядка, которые принимают функцию/метод и возвращают модифицированную версию. Они позволяют добавлять функциональность без изменения исходного кода. Я использую декораторы постоянно в production коде.
Базовый синтаксис
# Простой декоратор
def my_decorator(func):
def wrapper(*args, **kwargs):
print(f"До вызова {func.__name__}")
result = func(*args, **kwargs)
print(f"После вызова {func.__name__}")
return result
return wrapper
@my_decorator
def greet(name):
return f"Привет, {name}"
print(greet("Иван"))
# До вызова greet
# После вызова greet
Примеры декораторов из реальной практики
1. Логирование (logging)
import functools
import logging
logger = logging.getLogger(__name__)
def log_calls(func):
@functools.wraps(func) # Сохраняет __name__, __doc__ оригинальной функции
def wrapper(*args, **kwargs):
logger.info(f"Вызов {func.__name__} с args={args}, kwargs={kwargs}")
try:
result = func(*args, **kwargs)
logger.info(f"Результат: {result}")
return result
except Exception as e:
logger.error(f"Ошибка в {func.__name__}: {e}")
raise
return wrapper
@log_calls
def process_payment(user_id, amount):
return f"Payment {amount} for user {user_id} processed"
2. Кеширование (memoization)
from functools import lru_cache
@lru_cache(maxsize=128)
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(35)) # Вычисляется за миллисекунды благодаря кешу
3. Проверка авторизации (auth guard)
from functools import wraps
from fastapi import HTTPException
def require_auth(func):
@wraps(func)
def wrapper(request, *args, **kwargs):
if not request.user or not request.user.is_authenticated:
raise HTTPException(status_code=401, detail="Not authenticated")
return func(request, *args, **kwargs)
return wrapper
@require_auth
def get_user_profile(request):
return {"user_id": request.user.id}
4. Retry с экспоненциальной задержкой
import time
from functools import wraps
def retry(max_attempts=3, delay=1):
def decorator(func):
@wraps(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
wait_time = delay * (2 ** attempt) # Экспоненциальный backoff
print(f"Attempt {attempt + 1} failed. Retrying in {wait_time}s...")
time.sleep(wait_time)
return wrapper
return decorator
@retry(max_attempts=3, delay=1)
def unstable_api_call():
# Может выбросить исключение
import random
if random.random() < 0.7:
raise Exception("API unavailable")
return "Success"
5. Проверка типов (validation)
from functools import wraps
from typing import get_type_hints
def validate_types(func):
@wraps(func)
def wrapper(*args, **kwargs):
hints = get_type_hints(func)
# Проверяем типы аргументов
for i, (arg_name, arg_type) in enumerate(list(hints.items())[:-1]):
if not isinstance(args[i], arg_type):
raise TypeError(f"{arg_name} должен быть {arg_type}, получен {type(args[i])}")
return func(*args, **kwargs)
return wrapper
@validate_types
def add(a: int, b: int) -> int:
return a + b
print(add(1, 2)) # OK
print(add("1", "2")) # TypeError
6. Rate limiting
from functools import wraps
import time
from collections import defaultdict
class RateLimiter:
def __init__(self, calls, period):
self.calls = calls
self.period = period
self.history = defaultdict(list)
def __call__(self, func):
@wraps(func)
def wrapper(*args, **kwargs):
now = time.time()
call_history = self.history[func.__name__]
# Удаляем старые вызовы
call_history[:] = [t for t in call_history if now - t < self.period]
if len(call_history) >= self.calls:
raise Exception(f"Rate limit exceeded for {func.__name__}")
call_history.append(now)
return func(*args, **kwargs)
return wrapper
limiter = RateLimiter(calls=5, period=60)
@limiter
def api_endpoint():
return {"status": "ok"}
7. Параметризованный декоратор (timing)
from functools import wraps
import time
def timer(func):
@wraps(func)
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
elapsed = time.time() - start
print(f"{func.__name__} took {elapsed:.4f} seconds")
return result
return wrapper
@timer
def slow_function():
time.sleep(0.1)
return "Done"
slow_function() # slow_function took 0.1000 seconds
8. Класс как декоратор
class Counter:
def __init__(self, func):
self.func = func
self.count = 0
def __call__(self, *args, **kwargs):
self.count += 1
print(f"Функция вызвана {self.count} раз")
return self.func(*args, **kwargs)
@Counter
def hello():
return "Hello"
hello() # Функция вызвана 1 раз
hello() # Функция вызвана 2 раз
Встроенные декораторы Python
class MyClass:
@property # Превращает метод в свойство
def name(self):
return self._name
@staticmethod # Не требует self
def static_method():
return "static"
@classmethod # Получает класс вместо self
def from_dict(cls, data):
return cls(**data)
Выводы: декораторы — это мощный паттерн для разделения concerns (логирование, кеширование, авторизация). Правильное использование делает код чище и переиспользуемым.