Ответ
Ответ не найден.
Ответ 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). Главное — не переборщить, а то вместо читаемого кода получится матрёшка из обёрток, в которой сам чёрт ногу сломит. Пользуйся на здоровье, но с чувством, с толком, с расстановкой.