class cached_property: def __init__(self, method): self._method = method def __get__(self, instance, owner): if instance is None: return self value = self._method(instance) setattr(instance, self._method.__name__, value) return valueПример использования:
class A: @cached_property def f(self): return 42a = A()
a.f
При вызове первый раз на чтение атрибута
f non-data дескриптор f() реализованный через декоратор @cached_property вызовется один раз и перезапишет вычисленное значение в атрибут экземпляра класса A - fСтатические методы класса
class SomeClass: @staticmethod def do_something(): passSomeClass.do_something()Метод класса возвращающий экземпляр класса для организации хитрых инициализаций
class Settings: @classmethod def read_from(cls, path): res = cls() # do smth with path return resSettings.read_from("settings.ini")@classmethod гарантирует, что read_from будет вызван не с экземпляром класса, а с классом@staticmethod гарантирует, что первым параметром не будет self, пользы не много, зато можно подчеркнуть, что данный метод статичен по отношению к экземпляру класса__new__ - создает экземпляр класса, т.е. это конструктор возвращяющий экземпляр, например так:return super().__new__(cls)class ImpossibleIsNothing(metaclass=lambda *args, **kwargs: 42): passПревращает класс в число.
С помощью метаклассов можно сделать любое изменение класса и результат metaclass-а запишется в имя класса.
Метаклассы могут изменять тип словаря в котором хранятся атрибуты класса через метод
__prepare__В отличие от декораторов метаклассы наследуются потомками, т.е. не нужно каждый раз декорировать потомков для реализации задуманного поведения
Metaclasses are deeper magic than 99% of users should ever worry about. If you wonder whether you need them, you don't (the people who actually need them know with certainty that they need them, and don't need an explanation about why).— Тим Питерс
В стандартной библиотеке есть модуль
abc, который с помощью metaclass-ов позволяет писать абстрактные классы в pythonimport abcclass Iterable(metaclass=abc.ABCMeta): @abc.abstractmethod def __iter__(self): passclass Something(Iterable): pass>>> Something()TypeError: Can't instantiate abstract class Something with abstract methods __iter__Модуль
collections.abc содержит абстрактные базовые классы для различных коллекцийНапример, чтобы реализовать словарь запоминающий только последние несколько элементов и чтобы методы
setdefault и аналогичные работали, необходимо его унаследовать от MutableMapping и реализовать методы: __getitem__, __setitem__, __delitem__, __iter__, __len__