Дескриптор вы в приведенном примере является дескриптором данных.
После установки атрибута, как и любой другой дескриптор данных, он занимает самый высокий приоритет и называется так:
type(myinst).__dict__["attr"].__set__(myinst, 1234)
Это, в свою очередь, добавляет attr
в словарь экземпляра согласно вашему методу __set__
.
После доступа к атрибутам, дескриптор проверяется имеющий метод __get__
, но терпит неудачу, в результате чего для поиска будет перенаправлен словарю экземпляра следующим образом:
myinst.__dict__["attr"]
Если он не найден в словаре экземпляра , сам дескриптор возвращается.
Такое поведение вскоре задокументированы в data model так:
Если он не определяет __get__()
, а затем получить доступ к атрибуту будет возвращать сам объект дескриптора, если нет значение в словаре экземпляра в объекта ,
Обычные способы использования включают в себя предотвращение использования в дескрипторах словарей {instance: value}
и эффективных значений кеширования.
В Python 3.6, __set_name__
был добавлен в протокол дескриптора, таким образом, устраняя необходимость в указании имени внутри дескриптора. Таким образом, ваш дескриптор может быть записан следующим образом:
class Desc:
def __set_name__(self, owner, name):
self.name = name
def __set__(self, inst, value):
inst.__dict__[self.name] = value
print("set", self.name)
class Test:
attr = Desc()
Что касается поведения документированного в модели данных, есть более полное описание в Реймонд [как] (https://docs.python.org/2/ howto/descriptor.html). – wim
@wim На самом деле, причина, по которой я поднял этот вопрос поначалу, состоит в том, что там не документировано. Ничто не учитывает дескриптор данных без '__get__'. Подумал, как это работает. Я добавлю это к pydocs, я думаю. – Bharel