Декораторы классов, как и декораторы функций, являются мощной функцией в 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, как в других языках. Эффект синглетона обычно лучше реализуется в виде глобальной переменной в модуле.