Понимание дескрипторов Python

Я пытаюсь лучше понять дескрипторы.

Я не понимаю, почему в методе foo не вызывается метод дескрипторов __get__.

Насколько я понимаю дескрипторы, метод __get__ всегда вызывается, когда я обращаюсь к атрибуту объекта с помощью оператора точки или когда я использую __getattribute__().

Согласно документации Python:

class RevealAccess(object):
    def __init__(self, initval=None, name='var'):
        self.val = initval
        self.name = name

    def __get__(self, obj, objtype):
        print('Retrieving', self.name)
        return self.val

    def __set__(self, obj, val):
        print('Updating', self.name)
        self.val = val

class MyClass(object):
    x = RevealAccess(10, 'var "x"')
    y = 5

    def foo(self):
        self.z = RevealAccess(13, 'var "z"')
        self.__getattribute__('z')
        print(self.z)

m = MyClass()
m.foo()
m.z # no print
m.x # prints var x

person GarlicPasta    schedule 28.04.2015    source источник
comment
Я не совсем понимаю, в чем твоя проблема?   -  person user3467349    schedule 28.04.2015
comment
@ user3467349: m.z и m.x оба являются экземплярами класса RevealAccess, который реализует протокол дескриптора. ОП ожидал, что протокол будет использоваться как для m.z, так и для m.x.   -  person Martijn Pieters    schedule 28.04.2015
comment
@ user3467349: например. вам нужно понять, что такое протокол дескриптора это, прежде чем вы сможете ответить на вопрос.   -  person Martijn Pieters    schedule 28.04.2015
comment
m.z возвращает именно тот экземпляр, который был назначен ему для меня, я все еще не уверен, каков здесь ожидаемый результат?   -  person user3467349    schedule 28.04.2015
comment
Он хочет позвонить m.z.__getattribute__ ? MyClass не является подклассом RevealClass...   -  person user3467349    schedule 28.04.2015
comment
@ user3467349: нет, не знают. Они читают документацию по протоколу дескриптора, в которой объясняется, что доступ к атрибутам на m обрабатывается type(m).__getattribute__(attribute) и именно там выполняется протокол дескриптора.   -  person Martijn Pieters    schedule 29.04.2015
comment
@ user3467349: ожидаемый результат Retrieving var "z"; например был вызван метод RevealAccess.__get__.   -  person Martijn Pieters    schedule 29.04.2015
comment
@MartijnPieters Документы не предполагают, что метод RevealAccess.__get__ вообще будет вызываться, если только вы не читаете что-то отличное от того, что связано с OP.   -  person user3467349    schedule 29.04.2015
comment
@ user3467349: в разделе «Вызов дескрипторов» описан процесс. Пример в вопросе взят непосредственно из этого HOWTO.   -  person Martijn Pieters    schedule 29.04.2015
comment
@ user3467349: Нет, протокол дескриптора не используется для атрибутов экземпляра, как объясняется в моем ответе. RevealAccess.__get__ вызывается при доступе к m.x.   -  person Martijn Pieters    schedule 29.04.2015


Ответы (1)


z — это атрибут экземпляра, а не класса. Протокол дескриптора применяется только к атрибутам, извлеченным из класса.

Из DEscriptor HOWTO:

Для объектов механизм находится в object.__getattribute__(), который преобразует b.x в type(b).__dict__['x'].__get__(b, type(b)).

и в разделе Реализация дескрипторов. модели данных Python:

Следующие методы применяются только тогда, когда экземпляр класса, содержащего метод (так называемый класс дескриптора), появляется в классе владельца (дескриптор должен находиться либо в классе владельца, словарь класса или в словаре класса для одного из его родителей).

Ваш m.z не может быть найден в словаре класса; type(m).__dict__['z'] не существует; вместо этого он находится в m.__dict__['z']. Здесь m — это экземпляр, а класс ownerMyClass, а z отсутствует в словаре класса owner.

person Martijn Pieters    schedule 28.04.2015