Был ли на собеседовании момент, который показался вам нестандартным?

Ответ

Ответ не найден.

Ответ 18+ 🔞

Боже, ну и тема у нас сегодня, аж самому интересно стало, пока писал. Смотри, есть такая штука в Python — декораторы. Представь себе, ты написал функцию, она у тебя работает, всё пиздато. Но потом тебе вдруг понадобилось, чтобы перед каждым её запуском в консоль писалась хуйня типа "Функция стартанула, ёпта!" или чтобы замерялось время выполнения. И что, ты теперь будешь в каждую функцию эту строчку вписывать? Да ну нахуй, это же пиздец какой рутиной станет.

Вот тут-то декораторы и выручают, как родные. Это такая обёртка, которая принимает твою функцию, делает вокруг неё какую-то свою магию, а потом возвращает тебе уже модифицированную версию. Красота же!

Смотри, как это выглядит в самом простом виде, без всяких там сахарных синтаксисов:

def мой_декоратор(старая_функция):
    def новая_функция(*args, **kwargs):
        print("Сейчас вызову какую-то дичь...")
        результат = старая_функция(*args, **kwargs)
        print("Всё, отработала. Можно идти пить чай.")
        return результат
    return новая_функция

def моя_обычная_функция():
    print("Я просто функция, делаю свои дела.")

# Обёртываем нашу функцию в декоратор
украшенная_функция = мой_декоратор(моя_обычная_функция)

# Теперь вызываем уже обёрнутую версию
украшенная_функция()

Запустишь этот код — и увидишь, что наша обычная функция теперь обрамлена принтами из декоратора. Волшебство, блядь!

Но писать украшенная_функция = мой_декоратор(моя_обычная_функция) — это же ебать какой многословно. Поэтому умные дядьки придумали специальный синтаксис, "@" — называется "синтаксический сахар". И выглядит это уже куда приятнее:

def мой_декоратор(func):
    def wrapper(*args, **kwargs):
        print("Начинается какая-то дичь...")
        result = func(*args, **kwargs)
        print("Дичь завершена.")
        return result
    return wrapper

# Вот он, красавец, знак "@"
@мой_декоратор
def моя_крутая_функция(x, y):
    print(f"Складываю {x} и {y}")
    return x + y

# Вызываем как обычно, но работает она уже с обёрткой
сумма = моя_крутая_функция(5, 3)
print(f"Результат: {сумма}")

Теперь при вызове моя_крутая_функция автоматически применится декоратор. Удобно, ёпта!

А теперь смотри, где реальная сила и где можно обосраться с настройками. Допустим, твой декоратор должен принимать аргументы. Например, ты хочешь, чтобы он логировал сообщение, которое ты сам задашь. Тогда нужно делать декоратор, который возвращает... другой декоратор. Звучит как "хуй в квадрате", но на деле логично.

def логирующий_декоратор(сообщение_из_логгера="Вызов функции"):
    # Это внешняя функция, которая принимает аргумент декоратора
    def реальный_декоратор(func):
        # А это уже сам декоратор, который принимает функцию
        def wrapper(*args, **kwargs):
            print(f"[ЛОГ] {сообщение_из_логгера}: {func.__name__}")
            return func(*args, **kwargs)
        return wrapper
    return реальный_декоратор

# Применяем с кастомным сообщением
@логирующий_декоратор("Сейчас будет сложение, блядь!")
def сложить(a, b):
    return a + b

# Или с дефолтным
@логирующий_декоратор()
def вычесть(a, b):
    return a - b

print(сложить(10, 5))
print(вычесть(10, 5))

Вот так, сука, ты можешь параметризовать поведение декоратора. Мощная штука, если использовать с умом, а не просто для понтов.

Главная засада, о которую все ебут мозги — это то, что декоратор меняет имя и документацию исходной функции. wrapper же возвращается вместо неё. Это может сломать introspection (когда код смотрит на сам себя). Для борьбы с этим есть functools.wraps. Просто импортируй его и примени внутри wrapper:

from functools import wraps

def умный_декоратор(func):
    @wraps(func)  # Вот эта магия сохраняет метаданные
    def wrapper(*args, **kwargs):
        print("Что-то делаем перед...")
        return func(*args, **kwargs)
    return wrapper

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