Декораторы Python

Декоратор — это продвинутая возможность в Python, используемая длядинамического расширения функциональности функций или классов без изменения исходного кода функции。

По сути, декоратор — это функция: он принимает функцию в качестве аргумента и возвращает новую функцию (обычно улучшенную версию исходной функции).

Декораторы применяются с помощью синтаксиса@decorator_name, размещаемого перед определением функции или метода.

Python также предоставляет некоторые встроенные декораторы, такие как@staticmethodи@classmethod。

Типичные случаи использования:

  • Логирование:Запись информации о вызовах функций, параметрах и возвращаемых значениях
  • Статистика производительности:Измерение времени выполнения функции
  • Контроль доступа:Ограничение прав доступа к функции
  • Кэширование:Кэшировать результаты функции для повышения производительности

Базовый синтаксис

Основная идея декоратора:использование одной функции для "обёртывания" другой функции。

Синтаксис

def decorator_function(original_function):
    def wrapper(*args, **kwargs):
        # Перед вызовом
        print("Перед выполнением")

        result = original_function(*args, **kwargs)

        # После вызова
        print("После выполнения")

        return result
    return wrapper

@decorator_function
def target_function():
    print("Выполнение исходной функции")

Пояснение:

  • decorator_function: функция-декоратор (получает исходную функцию)
  • wrapper: функция-обёртка (фактически выполняется)
  • @decorator_function: эквивалентно замене функции

Эквивалентная форма:

target_function = decorator_function(target_function)

👉 При вызовеtarget_function(), фактически выполняетсяwrapper()


Использование декораторов

Декораторы применяются с помощью@синтаксического сахара, размещаемого перед определением функции:

@time_logger
def target_function():
    pass

Эквивалентно:

def target_function():
    pass

target_function = time_logger(target_function)

Этот механизм позволяет единообразно добавлять функциональность (например, логирование, проверку прав и т. д.) без изменения исходной функции.


Пример: вывод логов

def my_decorator(func):
    def wrapper():
        print("Before function execution")
        func()
        print("After function execution")
    return wrapper

@my_decorator
def say_hello():
    print("Hello!")

say_hello()

Вывод:

函数执行前
Hello!
函数执行后
  • my_decoratorПолучаетsay_hello
  • @my_decoratorЗаменяет исходную функцию

Декораторы с параметрами

Если у исходной функции есть параметры, нужно вwrapperиспользовать*args, **kwargs:

Пример

def my_decorator(func):
    def wrapper(*args, **kwargs):
        print("Перед выполнением")
        func(*args, **kwargs)
        print("После выполнения")
    return wrapper

@my_decorator
def greet(name):
    print(f"Привет, {name}!")

greet("Alice")

Вывод:

执行前
Hello, Alice!
执行后

Пояснение:Использование*args, **kwargsможет принимать функции с любым количеством параметров.


Декораторы с параметрами (продвинутый уровень)

def repeat(num_times):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(num_times):
                func(*args, **kwargs)
        return wrapper
    return decorator

@repeat(3)
def say_hello():
    print("Hello!")

say_hello()

Пояснение:Это «фабрика декораторов»; внешняя функция используется для получения параметров.

Hello!
Hello!
Hello!


Декораторы классов

Помимо функций, декораторы также можно применять к классам.

Декоратор класса получает класс и возвращает изменённый класс или класс-обёртку.

  • Расширять методы класса
  • Управлять процессом создания экземпляров
  • Реализовывать функциональность, такую как синглтоны и логирование

Декораторы классов на основе функций

Пример

def log_class(cls):
    class Wrapper:
        def __init__(self, *args, **kwargs):
            self.wrapped = cls(*args, **kwargs)

        def __getattr__(self, name):
            return getattr(self.wrapped, name)

        def display(self):
            print("Перед вызовом")
            self.wrapped.display()
            print("После вызова")

    return Wrapper

@log_class
class MyClass:
    def display(self):
        print("Исходный метод")

obj = MyClass()
obj.display()
Before call
Original method
After call

Декораторы классов, основанные на классах

Пример: шаблон «Одиночка»

class SingletonDecorator:
    def __init__(self, cls):
        self.cls = cls
        self.instance = None

    def __call__(self, *args, **kwargs):
        if self.instance is None:
            self.instance = self.cls(*args, **kwargs)
        return self.instance

@SingletonDecorator
class Database:
    def __init__(self):
        print("Инициализация")

db1 = База данных()
db2 = База данных()
print(db1 is db2)
初始化
True

Встроенные декораторы

Часто используемые встроенные декораторы:

  1. @staticmethod: определяет статический метод
  2. @classmethod: определяет метод класса
  3. @property: превращает метод в свойство

Пример

class MyClass:
    @staticmethod
    def static_method():
        print("Статический метод")

    @classmethod
    def class_method(cls):
        print(cls.__name__)

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, value):
        self._name = value

Наложение нескольких декораторов

Несколько декораторовоборачивают снизу вверх на этапе определения,и выполняются сверху вниз на этапе вызова:

Пример

def decorator1(func):
    def wrapper():
        print("Decorator 1")
        func()
    return wrapper

def decorator2(func):
    def wrapper():
        print("Decorator 2")
        func()
    return wrapper

@decorator1
@decorator2
def say_hello():
    print("Hello!")

say_hello()

Итоговый вывод:

Decorator 1
Decorator 2
Hello!

Краткое резюме

Decorator = a function that wraps a function + extending functionality without modifying the original code
  • Синтаксис @ по сути представляет собой замену функции
  • wrapper — это функция, которая фактически выполняется
  • Рекомендуется использовать *args, **kwargs для большей универсальности
  • Поддерживает функции, классы и даже декораторы с параметрами
Другие расширения