Что такое декоратор в Python?

Ответ

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

Пример простого декоратора для логирования:

def logger(func):
    def wrapper(*args, **kwargs):
        print(f'Вызов функции {func.__name__} с аргументами: {args}, {kwargs}')
        result = func(*args, **kwargs)
        print(f'Функция {func.__name__} вернула: {result}')
        return result
    return wrapper

@logger
def add(a, b):
    return a + b

# Вызов обёрнутой функции
add(5, 3)
# Вывод:
# Вызов функции add с аргументами: (5, 3), {}
# Функция add вернула: 8

Синтаксис @decorator — это просто «синтаксический сахар» для add = logger(add). Для сохранения метаданных исходной функции (например, __name__) рекомендуется использовать functools.wraps.

Ответ 18+ 🔞

А, декораторы в Python! Ну это ж, ёпта, просто золотая жила для ленивых, но хитрых программистов. Представь себе: есть у тебя функция, которая делает своё дело, а ты такой — «хочу, чтобы она ещё и логировала каждый свой чих, но лезть внутрь и ковырять её код — терпения ноль, ебать».

Вот тут-то декоратор и выручает, как верный друг. По сути, это такая функция-обёртка, которая хватает твою родную функцию за жопу, наряжает её в дополнительные действия и отдаёт тебе обратно уже новую, улучшенную версию. Всё это без единого правка в оригинале! Красота же, блядь.

Смотри, вот тебе классический пример — декоратор для логирования. Чистая магия, хуй с горы.

def logger(func):
    def wrapper(*args, **kwargs):
        print(f'Вызов функции {func.__name__} с аргументами: {args}, {kwargs}')
        result = func(*args, **kwargs)
        print(f'Функция {func.__name__} вернула: {result}')
        return result
    return wrapper

@logger
def add(a, b):
    return a + b

# Вызов обёрнутой функции
add(5, 3)
# Вывод:
# Вызов функции add с аргументами: (5, 3), {}
# Функция add вернула: 8

Видишь эту собачку @logger над функцией add? Это и есть тот самый волшебный пинок. Всё, что она делает — это подменяет твою старую add на новую, которую вернул logger. По-честному, это то же самое, что написать add = logger(add). Просто так, с собачкой, выглядит как будто ты накинул на функцию плащ-невидимку с суперспособностями.

А теперь главный подвох, из-за которого все начинающие охуевают. После такой подмены у твоей функции add меняется имя! Она теперь будет зваться не add, а wrapper, потому что именно эту внутреннюю функцию мы и вернули. Это, конечно, пиздец как неудобно, когда что-то ломается и в логах ты видишь кучу одинаковых wrapper.

Чтобы не было такого конфуза, умные дядьки придумали functools.wraps. Эта штука как раз копирует все метаданные оригинальной функции (имя, документацию и прочее) в нашу обёртку. Без неё — ты распиздяй, с ней — молодец.

Короче, декораторы — это овердохуища мощный инструмент. Хочешь кешировать результаты, проверять авторизацию, замерять время выполнения — вешай декоратор и не парься. Главное — понять эту идею обёртки, а дальше уже можно творить, что душе угодно.