Что такое декораторы в Python и для чего они используются

Ответ

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

По сути, декоратор является "синтаксическим сахаром" для функций высшего порядка.

Запись с использованием @:

@my_decorator
def say_hello():
    print("Hello!")

Эквивалентна следующей конструкции:

def say_hello():
    print("Hello!")

say_hello = my_decorator(say_hello)

Основные сценарии использования:

  • Логирование: Запись информации о вызове функции, ее аргументах и результате.
  • Кеширование: Сохранение результатов выполнения функции для повторного использования (например, functools.lru_cache).
  • Проверка прав доступа: Проверка, имеет ли пользователь право на выполнение определенного действия.
  • Замер времени выполнения: Измерение производительности функции.
  • Валидация данных: Проверка корректности аргументов, передаваемых в функцию.

Практический пример — декоратор для замера времени:

import time

def timing_decorator(func):
    def wrapper(*args, **kwargs):
        start_time = time.perf_counter()
        result = func(*args, **kwargs)
        end_time = time.perf_counter()
        print(f"Функция '{func.__name__}' выполнилась за {end_time - start_time:.4f} секунд")
        return result
    return wrapper

@timing_decorator
def process_data(size: int):
    """Имитирует долгую обработку данных."""
    time.sleep(1)
    print(f"Обработано {size} элементов.")
    return True

# Вызов декорированной функции
process_data(1000)

# Вывод:
# Обработано 1000 элементов.
# Функция 'process_data' выполнилась за 1.0012 секунд

Декораторы помогают следовать принципу DRY (Don't Repeat Yourself) и улучшают читаемость кода, отделяя основную бизнес-логику от вспомогательной (сквозной) функциональности.

Ответ 18+ 🔞

Слушай, ну вот объясняю тебе про декораторы в Python, как будто ты вчера родился, но уже хочешь в программисты. Это ж, блядь, такая штука, которая берёт твою обычную функцию, как вот эту, и натягивает на неё сверху, как презерватив, ещё один слой логики. А внутри-то функция та же самая, пизда, но теперь она в костюме супергероя.

Понимаешь, это как взять бутерброд и обернуть его в золотую фольгу. Вкус тот же, но подача — охуенно.

Вот смотри, этот собачий синтаксис с @:

@my_decorator
def say_hello():
    print("Hello!")

Это просто пиздатый способ не писать вот эту хуйню каждый раз:

def say_hello():
    print("Hello!")

say_hello = my_decorator(say_hello)

Одно и то же, ёпта! Просто первый вариант — красивый, а второй — для мазохистов.

А зачем это, спросишь, на хуй нужно?

  • Логирование: Чтобы знать, кто, когда и с какими аргументами твою функцию ебал. Полезно, когда всё падает и ты не понимаешь, в каком месте.
  • Кеширование: Чтобы не вычислять одно и то же по сто раз. Сказал «Привет, Вася» — запомнил. В следующий раз просто достал из кармана готовый ответ, а не думал заново.
  • Проверка прав: Ты чё, сюда лезешь? У тебя есть пропуск? Нет? Тогда пошёл на хуй, функция не для тебя.
  • Замер времени: Чтобы понять, почему твой код работает медленнее, чем черепаха в сиропе.
  • Валидация данных: А ну-ка покажи, что ты мне в функцию суёшь! А, вот это говно? Не, братан, так не пойдёт.

Вот тебе живой пример, чтоб совсем понятно стало. Декоратор, который засекает время:

import time

def timing_decorator(func):
    def wrapper(*args, **kwargs):
        start_time = time.perf_counter()
        result = func(*args, **kwargs)  # А вот тут сама функция и работает
        end_time = time.perf_counter()
        print(f"Функция '{func.__name__}' выполнилась за {end_time - start_time:.4f} секунд")
        return result
    return wrapper

@timing_decorator
def process_data(size: int):
    """Имитирует долгую обработку данных."""
    time.sleep(1)
    print(f"Обработано {size} элементов.")
    return True

# Вызов декорированной функции
process_data(1000)

# Вывод:
# Обработано 1000 элементов.
# Функция 'process_data' выполнилась за 1.0012 секунд

Видишь? Функция process_data просто спит и печатает. А декоратор @timing_decorator — это как хитрая жопа, которая стоит с секундомером и за всем следит. И главное — саму функцию process_data мы не трогали, ни строчки! Вот в чём, блядь, магия.

Короче, декораторы — это чтобы не повторять один и тот же код в каждой функции, как последний долбоёб. Принцип DRY, ёпта — Don't Repeat Yourself, или «Не будь говноедом». Отделил основную логику от всей этой обвязки — и живи спокойно, в рот меня чих-пых.