Ответ
Декораторы в Python — это мощный паттерн для добавления функциональности к существующим функциям или классам, не изменяя их исходный код. Их стоит использовать в следующих случаях:
- Логирование и отладка: Для отслеживания вызовов функций, их аргументов и времени выполнения.
- Кэширование (мемоизация): Для хранения результатов дорогостоящих вычислений и их повторного использования.
- Контроль доступа и аутентификация: Для проверки прав пользователя перед выполнением функции.
- Валидация данных: Для проверки входных или выходных аргументов функции.
- Изменение поведения (например, ретраи): Для автоматического повторения вызова функции при сбоях.
Пример: декоратор для логирования
import functools
import time
def log_execution_time(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
start_time = time.perf_counter()
result = func(*args, **kwargs)
end_time = time.perf_counter()
print(f"Функция {func.__name__!r} выполнена за {end_time - start_time:.4f} сек")
return result
return wrapper
@log_execution_time
def expensive_calculation(n):
return sum(i * i for i in range(n))
# При вызове будет выведено время выполнения
result = expensive_calculation(10000)
Использование декораторов делает код чище, так как сквозная функциональность (cross-cutting concern) выносится в отдельные, переиспользуемые компоненты.
Ответ 18+ 🔞
Давай разберемся с этими декораторами, а то народ их как будто боится, как черт ладана. На самом деле штука офигенная, если понять, зачем она нужна.
Представь, у тебя есть функция, которая просто делает свою работу. А потом тебе вдруг понадобилось засекать, сколько времени она работает. Ну, классика: «бля, почему всё так медленно?». Можно, конечно, внутрь функции запихнуть time.perf_counter(), но это же мудёж — копипастить одно и то же в каждую вторую функцию. Вот тут-то декоратор и выручает, как лучший друг.
Короче, когда их юзать:
- Логирование и отладка. Ты просто хочешь знать, что вообще происходит: что вызвалось, с какими аргументами и сколько времени оттяпало. Подозрение ёбаное чувствую, что без этого никуда.
- Кэширование. У тебя есть функция, которая, например, вычисляет число Пи до миллионного знака. Повторять это каждый раз — это просто терпения ноль, ёбать. Декоратор
@lru_cacheизfunctools— твой спаситель, он запомнит результат и в следующий раз отдаст его мгновенно. Волнение ёбать, когда понимаешь, насколько всё ускорилось. - Контроль доступа. «А ты кто такой, чтобы эту функцию вызывать?». Декоратор может проверить, авторизован ли пользователь или есть ли у него нужные права, прежде чем пускать его в святая святых. Доверия ёбать ноль в этом мире, так что такая штука жизненно необходима.
- Валидация данных. Функция ждет число, а ей прилетает строка? Декоратор может отловить эту манду с ушами на входе и либо преобразовать, либо отправить вызывающего на три буквы, не засоряя саму бизнес-логику.
- Изменение поведения. Например, автоматические повторные попытки (ретраи). Сеть легла, база данных не ответила — декоратор может сам, без твоего участия, подождать и попробовать ещё разок. Ёпта, иногда это спасает просто.
Смотри, как это выглядит на практике. Пример декоратора для логирования времени:
import functools
import time
def log_execution_time(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
start_time = time.perf_counter()
result = func(*args, **kwargs) # Вызываем саму функцию
end_time = time.perf_counter()
print(f"Функция {func.__name__!r} выполнена за {end_time - start_time:.4f} сек")
return result
return wrapper
@log_execution_time # Вот он, магический синтаксический сахар!
def expensive_calculation(n):
return sum(i * i for i in range(n))
# При вызове теперь будет выводиться время
result = expensive_calculation(10000)
Суть в чём? Ты написал один раз декоратор log_execution_time, а теперь можешь ёбушки-воробушки навешивать его на любую функцию, просто написав @log_execution_time сверху. Вся функция остаётся чистой, а функциональность логирования прикручивается сверху, как наклейка. Красота же!
Итог: декораторы — это не какая-то пиздопроебибна для избранных, а нормальный рабочий инструмент, чтобы не повторять один и тот же код в ста разных местах. Освоил — и жизнь стала проще, сам от себя охуел, насколько аккуратнее код стал.