← Назад к вопросам

Какой механизм лежит в основе работы декоратора?

1.0 Junior🔥 231 комментариев
#Python Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Механизм работы декоратора

Декоратор в 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: сохраняет метаданные оригинальной функции
  • Порядок применения: при нескольких декораторах они применяются снизу вверх

Декораторы — мощный инструмент для написания чистого и переиспользуемого кода.

Какой механизм лежит в основе работы декоратора? | PrepBro