Ответ
Декоратор в Python — это функция, которая принимает другую функцию (или класс) и возвращает новую, модифицированную функцию, не изменяя исходный код. Это реализация паттерна «декоратор», позволяющая динамически добавлять поведение.
Пример декоратора для логирования:
import time
import functools
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__} выполнилась за {end_time - start_time:.4f} секунд")
return result
return wrapper
@log_execution_time
def calculate_factorial(n):
if n <= 1:
return 1
return n * calculate_factorial(n-1)
print(calculate_factorial(5))
# Вывод:
# calculate_factorial выполнилась за ... секунд
# 120
Почему это важно:
- Разделение ответственности: Позволяет вынести сквозную функциональность (логирование, кэширование, аутентификацию) из бизнес-логики.
- Повторное использование: Один декоратор можно применить ко многим функциям.
- Читаемость: Использование
@decoratorнад функцией явно указывает на добавленное поведение.
Ключевые моменты:
- Декораторы могут быть вложенными (
@decorator1 @decorator2). - Декораторы с аргументами требуют дополнительного уровня вложенности функций.
functools.wrapsиспользуется для корректной работы интроспекции (например,help()и имя функции).
Ответ 18+ 🔞
А, декораторы в питоне! Ну это, блядь, такая штука, которая берёт твою функцию и делает из неё как будто новую, но не трогает старый код. Представь, что у тебя есть обычная функция, а ты ей сверху, как шапку, надеваешь дополнительное поведение. Хуй с горы, а не магия.
Вот смотри, пример декоратора, который засекает время:
import time
import functools
def log_execution_time(func):
@functools.wraps(func) # Эта хуйня сохраняет нормальное имя функции, а то обзовётся wrapper и всё
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
@log_execution_time
def calculate_factorial(n):
if n <= 1:
return 1
return n * calculate_factorial(n-1)
print(calculate_factorial(5))
# Вывод:
# calculate_factorial выполнилась за ... секунд
# 120
А зачем это всё, спросишь? Да овердохуища причин!
- Чтобы не мешать всё в одну кучу: Вместо того чтобы в каждой функции писать одно и то же — логирование, проверку прав, кэширование — ты эту поебень выносишь в декоратор. Бизнес-логика чистая, а всякие служебные штуки — отдельно. Удивление пиздец, как удобно.
- Чтобы не повторяться: Написал один раз декоратор для логирования — и тыкай его на любые функции, как горячие пирожки. Экономия времени — ебать колотить.
- Читаемость: Видишь над функцией
@check_permissions— и сразу ясно, что тут проверка прав доступа. Не надо в код лезть, всё на виду.
Но есть нюансы, ёпта:
- Их можно навешивать друг на друга, как гирлянды на ёлку (
@decor1 @decor2). - Если хочешь передать декоратору аргументы (типа
@retry(attempts=5)), то придётся ещё одну обёрточную функцию написать — голова заболит, но привыкнешь. functools.wraps— это святое! Без него твоя декорированная функция будет называтьсяwrapper, иhelp()по ней выдаст какую-то дичь. Так что не забывай, а то сам от себя охуеешь потом при отладке.