Какой механизм лежит в основе работы декоратора?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Механизм работы декоратора
Декоратор в Python — это функция, которая принимает другую функцию или класс как аргумент и возвращает модифицированную версию этой функции или класса. В основе работы лежит концепция функций первого класса (first-class functions), когда функция может быть передана как аргумент и возвращена как результат.
Базовый принцип
Декоратор работает по схеме: оригинальная функция оборачивается в функцию-обёртку, которая может выполнить код ДО вызова оригинальной функции, ПОСЛЕ её вызова или вообще заменить её поведение.
def decorator(func):
def wrapper(*args, **kwargs):
print("Код выполняется ДО функции")
result = func(*args, **kwargs)
print("Код выполняется ПОСЛЕ функции")
return result
return wrapper
def greet(name):
print(f"Hello, {name}!")
greet = decorator(greet)
greet("Alice")
Синтаксический сахар @
Синтаксис @decorator — это просто удобная запись, эквивалентная func = decorator(func):
@decorator
def greet(name):
print(f"Hello, {name}!")
Сохранение метаданных функции
При использовании декоратора теряются метаданные (name, doc). Используй functools.wraps:
from functools import wraps
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__}")
return func(*args, **kwargs)
return wrapper
@decorator
def add(a, b):
"""Складывает два числа"""
return a + b
print(add.__name__) # 'add'
print(add.__doc__) # 'Складывает два числа'
Декоратор с параметрами
Для декоратора с параметрами нужна ещё одна функция-обёртка:
def repeat(times):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
for _ in range(times):
func(*args, **kwargs)
return wrapper
return decorator
@repeat(times=3)
def say_hello(name):
print(f"Hello, {name}!")
say_hello("Bob") # Выведет "Hello, Bob!" три раза
Декораторы классов
Декораторы работают и с классами. Часто используются для автоматической регистрации или добавления методов:
def add_greeting(cls):
def greet(self):
return f"Hello from {cls.__name__}!"
cls.greet = greet
return cls
@add_greeting
class Person:
def __init__(self, name):
self.name = name
p = Person("Alice")
print(p.greet()) # "Hello from Person!"
Практические примеры
1. Логирование вызовов:
def log_call(func):
@wraps(func)
def wrapper(*args, **kwargs):
print(f"Вызов {func.__name__}")
result = func(*args, **kwargs)
print(f"Результат: {result}")
return result
return wrapper
2. Проверка прав доступа:
def require_auth(func):
@wraps(func)
def wrapper(user, *args, **kwargs):
if not user.is_authenticated:
raise PermissionError("User not authenticated")
return func(user, *args, **kwargs)
return wrapper
3. Кэширование результатов:
def cache_result(func):
cache = {}
@wraps(func)
def wrapper(*args):
if args not in cache:
cache[args] = func(*args)
return cache[args]
return wrapper
Ключевые моменты
- Функции первого класса: функция может быть переменной, аргументом и результатом
- Замыкание (closure): wrapper запоминает оригинальную функцию из внешней области видимости
- *args, **kwargs: позволяют декоратору работать с функциями с любыми параметрами
- @wraps: сохраняет метаданные оригинальной функции
- Порядок применения: при нескольких декораторах они применяются снизу вверх
Декораторы — мощный инструмент для написания чистого и переиспользуемого кода.