Сообщить об ошибке.

Синтаксис декоратора класса в Python

Декораторы классов, как и декораторы функций, являются мощной функцией в Python. Однако вместо изменения функций декораторы классов применяются к классам. Их можно использовать для изменения поведения класса, добавления новых методов или новых свойств.

Распространенные случаи использования декораторов классов:

  • Добавление новых методов в класс
  • Добавление новых свойств в класс
  • Изменение поведения класса
  • Реализация кэширования на уровне классов

Синтаксис декоратора класса аналогичен синтаксису декоратора функции, но он применяется к классу. Определяется функция, которая принимает класс в качестве аргумента, каким-то образом модифицирует класс, а затем возвращает измененный класс. Вот пример декоратора класса, который добавляет новое свойство в класс:

def unique_add_property(unique_cls):
    unique_cls.unique_new_property = "Добавленное свойство класса"
    return unique_cls
 
@unique_add_property
class UniqueMyClass:
    unique_existing_property = "Это родное свойство класса"

Пример декоратора класса, который добавляет новый метод:

def my_decorator(cls):
    class NewClass:
        def __init__(self, *args, **kwargs):
            self.obj = cls(*args, **kwargs)

        def new_method(self):
            print("Это новый метод, добавленный декоратором.")

    return NewClass

@my_decorator
class MyClass:
    def __init__(self, value):
        self.value = value

    def say_hello(self):
        print(f"Hello {self.value}.")

my_object = MyClass("world")
my_object.say_hello()
my_object.new_method()

В этом примере функция my_decorator - это декоратор, который принимает на вход класс cls, создает новый класс NewClass, который добавляет дополнительное поведение, и возвращает этот новый класс.

Декоратор класса @my_decorator эффективно заменяет MyClass классом NewClass. Когда создается объект MyClass (который теперь фактически является объектом NewClass), у него появляется новый метод new_method().

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

def count_instances(cls):
    cls._count = 0
    cls._old_init = cls.__init__
    def new_init(self, *args, **kwargs):
        cls._count += 1
        cls._old_init(self, *args, **kwargs)
    cls.__init__ = new_init
    return cls

@count_instances
class MyClass:
    def __init__(self, x):
        self.x = x

a = MyClass(1)
b = MyClass(2)
print(MyClass._count) 
# 2

Создание синглтона при помощи декоратора класса.

Синглтон (Singleton) - это класс, имеющий только один экземпляр. В Python есть несколько синглетов, это None, True и False. Тот факт, что None является синглетом, позволяющий сравнивать None с помощью ключевого слова is:

if _func is None:
    return decorator_name
else:
    return decorator_name(_func)

Ключевое слово is возвращает True только для объектов, которые являются точно таким же экземпляром. Следующий декоратор @singleton превращает класс в 'singleton', сохраняя первый экземпляр класса в качестве атрибута. Последующие попытки создания экземпляра, будут возвращать сохраненный экземпляр:

import functools

def singleton(cls):
    """Делает класс Одноэлементным классом"""
    @functools.wraps(cls)
    def wrapper(*args, **kwargs):
        if not wrapper.instance:
            wrapper.instance = cls(*args, **kwargs)
        return wrapper.instance
    wrapper.instance = None
    return wrapper

@singleton
class TheOne:
    pass

Как можно заметить, этот декоратор класса следует тому же шаблону, что и декораторы функций.

Смотрим как он работает:

>>> one = TheOne()
>>> two = TheOne()
>>> id(one)
# 140551970875600
>>> id(two)
# 140551970875600
>>> one is two
# True

Примечание: Класс синглтон не так часто используются в Python, как в других языках. Эффект синглетона обычно лучше реализуется в виде глобальной переменной в модуле.