Какие использовал декораторы?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Декораторы в Python
Декораторы — это один из самых мощных инструментов в Python. Это функции, которые модифицируют другие функции или классы, не изменяя их исходный код. Я использовал их много раз в разных контекстах.
Что такое декоратор
Декоратор — это функция, которая принимает другую функцию (или класс) как аргумент и возвращает модифицированную версию:
def my_decorator(func):
def wrapper(*args, **kwargs):
print(f"Вызвана функция {func.__name__}")
result = func(*args, **kwargs)
print(f"Функция завершена")
return result
return wrapper
@my_decorator
def say_hello(name):
return f"Hello, {name}!"
print(say_hello("Alice"))
# Вывод:
# Вызвана функция say_hello
# Hello, Alice!
# Функция завершена
1. Встроенные декораторы
@property
Это самый часто используемый декоратор. Он превращает метод в свойство, доступное как атрибут:
class Temperature:
def __init__(self, celsius):
self._celsius = celsius
@property
def celsius(self):
return self._celsius
@property
def fahrenheit(self):
return (self._celsius * 9/5) + 32
@celsius.setter
def celsius(self, value):
self._celsius = value
temp = Temperature(20)
print(temp.celsius) # 20
print(temp.fahrenheit) # 68.0
temp.celsius = 30 # используется setter
@staticmethod и @classmethod
class Math:
@staticmethod
def add(a, b):
"""Статический метод, не требует self"""
return a + b
@classmethod
def from_string(cls, value_str):
"""Метод класса, первый параметр — класс"""
value = int(value_str)
return cls(value)
print(Math.add(5, 3)) # 8 (не нужно создавать объект)
2. Декораторы для логирования и отладки
Это очень полезно для отслеживания выполнения:
import functools
import time
from typing import Any, Callable
def log_calls(func: Callable) -> Callable:
@functools.wraps(func)
def wrapper(*args, **kwargs) -> Any:
print(f"Вызов: {func.__name__}({args}, {kwargs})")
result = func(*args, **kwargs)
print(f"Результат: {result}")
return result
return wrapper
@log_calls
def divide(a: float, b: float) -> float:
return a / b
divide(10, 2) # Логирует вызов и результат
3. Декоратор для кеширования (memoization)
Оптимизирует повторные вызовы функции:
import functools
def memoize(func):
cache = {}
@functools.wraps(func)
def wrapper(*args, **kwargs):
# Создаем ключ кеша
key = (args, tuple(sorted(kwargs.items())))
if key not in cache:
cache[key] = func(*args, **kwargs)
return cache[key]
return wrapper
@memoize
def fibonacci(n):
"""Вычисляет n-е число Фибоначчи"""
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(10)) # Очень быстро благодаря кешу
4. Декоратор для проверки типов
from typing import Any
import functools
def type_check(**expected_types):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
# Проверяем типы параметров
for param_name, param_value in kwargs.items():
if param_name in expected_types:
expected_type = expected_types[param_name]
if not isinstance(param_value, expected_type):
raise TypeError(
f"{param_name} должна быть {expected_type.__name__}, "
f"получена {type(param_value).__name__}"
)
return func(*args, **kwargs)
return wrapper
return decorator
@type_check(name=str, age=int)
def create_user(name, age):
return {"name": name, "age": age}
create_user(name="Alice", age=30) # OK
# create_user(name="Bob", age="thirty") # TypeError
5. Декораторы в FastAPI
Это один из самых практичных примеров. FastAPI использует декораторы везде:
from fastapi import FastAPI, Depends, HTTPException
from typing import Optional
app = FastAPI()
# Декоратор для роута
@app.get("/users/{user_id}")
async def get_user(user_id: int):
return {"user_id": user_id}
# Декоратор с зависимостями (Dependency Injection)
def verify_token(token: Optional[str] = None):
if not token:
raise HTTPException(status_code=401, detail="No token")
return token
@app.post("/protected")
async def protected_endpoint(token: str = Depends(verify_token)):
return {"message": "You are authenticated", "token": token}
6. Декоратор для обработки ошибок (retry)
Полезно для работы с внешними API или БД:
import functools
import time
from typing import Type
def retry(max_attempts: int = 3, delay: float = 1.0, exceptions: tuple = (Exception,)):
def decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
attempt = 0
while attempt < max_attempts:
try:
return func(*args, **kwargs)
except exceptions as e:
attempt += 1
if attempt >= max_attempts:
raise
print(f"Attempt {attempt} failed: {e}. Retrying in {delay}s...")
time.sleep(delay)
return wrapper
return decorator
@retry(max_attempts=3, delay=1.0, exceptions=(ConnectionError,))
def fetch_data_from_api(url: str):
# Может выбросить ConnectionError
pass
7. Декоратор для валидации в Django
from django.views.decorators.http import require_http_methods
from django.views.decorators.csrf import csrf_exempt
@require_http_methods(["GET", "POST"])
def my_view(request):
return HttpResponse("Only GET and POST are allowed")
@csrf_exempt # Отключить CSRF проверку (не рекомендуется)
def api_endpoint(request):
pass
8. Собственный декоратор для профилирования
Полезно для отладки производительности:
import functools
import time
def measure_time(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
start = time.perf_counter()
result = func(*args, **kwargs)
end = time.perf_counter()
print(f"{func.__name__} took {(end - start)*1000:.2f}ms")
return result
return wrapper
@measure_time
def slow_function():
time.sleep(1)
return "done"
slow_function() # slow_function took 1000.23ms
9. Составные декораторы
Можно применять несколько декораторов к одной функции:
@log_calls
@measure_time
@retry(max_attempts=3)
def fetch_data(url):
# Будет залогирована, будет измерено время, будет retry
pass
Важные практики
Всегда используй functools.wraps:
import functools
def my_decorator(func):
@functools.wraps(func) # Сохраняет __name__, __doc__ и метаданные
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
Без него теряются метаданные функции, и это может сломать документацию и отладку.
Декораторы — это мощный паттерн для DRY и разделения ответственности. Они позволяют добавлять функциональность (логирование, кеширование, валидацию) без изменения исходного кода функций.