Когда лучше использовать декоратор в Python?

Ответ

Декораторы в 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 сверху. Вся функция остаётся чистой, а функциональность логирования прикручивается сверху, как наклейка. Красота же!

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