Вы путаете вещи, используя имя value
для двух вещей: один атрибут Cls
, а его значение - объект дескриптора. Другой атрибут этого объекта дескриптора, и это тот, чье значение является строкой.
Главное, чтобы помнить, что существует только один объект дескриптора, используемый для всех экземпляров класса. Когда вы делаете self.value = start
в своем методе __set__
, self
ссылается на объект дескриптора, поэтому вы устанавливаете атрибут «значение» для самого объекта дескриптора, а не для экземпляра Cls
. (Если вы измените его на instance.value = start
вместо этого, вы получите ошибку рекурсии, так что будет пытаться вызвать __set__
снова.)
Вы увидите, что происходит, если вы создаете несколько экземпляров своего класса:
>>> x = Cls("oops")
In Descriptor's __set__ method
>>> y = Cls("dang")
In Descriptor's __set__ method
>>> x.value
In Descriptor's __get__method
'dang'
>>> Cls.__dict__['value'].value
'dang'
Обратите внимание, что создание y
изменено x.value
. Это связано с тем, что существует только один объект дескриптора, и он имеет только один атрибут «значение», поэтому значение используется для всех экземпляров Cls
.
Непонятно, чего вы пытаетесь достичь здесь, поэтому трудно сказать, как «исправить» это. Некоторые общие принципы:
- Не используйте
self
в __get__
и __set__
, если вы не хотите хранить информацию на уровне класса. Чтобы хранить данные, специфичные для экземпляра, вам необходимо использовать instance
.
- Даже если вы делаете это, не используйте одно и то же имя для самого атрибута дескриптора и скрытого атрибута, где он хранит свои данные, или вы будете наступать на собственные пальцы.
- Если вы хотите сделать что-то действительно фантастическое, вы, вероятно, можете просто использовать
property
и не писать свой собственный дескриптор вообще. Если вы «исправили» дескриптор, который вы написали выше, он все равно будет бесполезен, потому что он не сделает ничего, что property
еще не делает.
Вы понимаете, как работает протокол дескриптора? Потому что то, что вы описываете, похоже на то, как оно работает. Протокол дескриптора активируется, когда вы выполняете 'obj.value'. Он не активируется, когда вы выполняете 'obj .__ dict __ ['value']'. – BrenBarn
Это означает, что есть значение, которое ссылается на строковый объект «hello» в пространстве имен Cls. Тогда есть другое значение, ссылающееся на объект дескриптора, который тоже находится в пространстве имен Cls. – user634615
У вас есть недоразумение. 'self' внутри ваших методов' __set__'/'__get__' относится к самому дескрипторному объекту, а не к экземпляру' Cls'. См. Мой отредактированный ответ. – BrenBarn