Порядок поиска obj.x:
- data-дескриптор в классе (и его предках) — вызвать его
__get__; obj.__dict__["x"];- non-data дескриптор или обычный атрибут класса.
Свой дескриптор — валидация:
class Positive:
def __set_name__(self, owner, name):
self.name = "_" + name
def __get__(self, obj, objtype=None):
return getattr(obj, self.name)
def __set__(self, obj, value):
if value <= 0:
raise ValueError("должно быть > 0")
setattr(obj, self.name, value)
class Order:
qty = Positive()
def __init__(self, qty): self.qty = qty
Методы. Функция в классе — non-data дескриптор: obj.method через __get__ возвращает связанный метод, подставляющий obj как self. staticmethod возвращает функцию без связывания, classmethod — связывает с классом.
property — data-дескриптор, вызывающий заданные геттер, сеттер, делитер.
Ленивое вычисление: functools.cached_property — non-data дескриптор: первый вызов кладёт результат в __dict__ экземпляра, и дальше словарь перекрывает дескриптор.