🔸 Вместо класса создаем свойства для его мета-класса
class CMeta(type):При этом можем изменить дефолтное значение для унаследованного класса. Плюс, как и в обычном property можно сделать getter, setter и deleter.
_x = 0
@property
def x(cls):
return cls._x
@x.setter
def x(cls, value):
cls._x = value
class C(metaclass=CMeta):
_x = 2
>>> C.xПроверим, действительно ли сработал setter или мы просто перезаписали атрибут
2
>>> C.x = 34
>>> C.x
34
x
>>> C._xДа, всё верно! 😎
34
🔸 Динамический атрибут класса. Похож на прошлый пример но с дополнительной фишкой.
Что он делает? Этот декоратор не только позволяет добавить свойство класса но и разделить функционал для свойства класса и свойства инстанса.
Работает это через дополнительный вызов
__getattr__ и __setattr__ мета-класса, где требуется проверить имя атрибута и сделать соответствующие выводы.from types import DynamicClassAttribute#tricks
class CMeta(type):
def __getattr__(self, item):
if item == 'x': # проверка имени
return 'x from class'
raise AttributeError
def __setattr__(self, key, value):
print('set class', key, '=', value)
class C(metaclass=CMeta):
@DynamicClassAttribute
def x(self):
return 'x from instance'
@x.setter
def x(self, value):
print('set instance x =', value)
>>> C.x
'from class'
>>> C().x
'from instance'
>>> C.x = 2
'set class x = 2'
C().x = 2
'set instance x = 2'