Данные Python и дескрипторы не данных

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

Дескрипторы данных с __set__() а также __get__() определенные всегда переопределяют переопределение в словаре экземпляра.

У меня нет проблем с пониманием этого предложения, но может ли кто-нибудь объяснить мне, почему такое правило действует? В конце концов, если я хочу переопределить атрибут в словаре экземпляра, мне уже нужно сделать это явно (inst.__dict__["attr"] = valкак наивный inst.attr = val назвал бы дескриптор __set__ метод, который (обычно) не переопределяет атрибут в словаре экземпляра.

редактировать: просто чтобы прояснить, я понимаю, что происходит, мой вопрос о том, почему такое правило было введено в действие.

1 ответ

Переопределение применяется к дескрипторам, которые являются частью класса __dict__,

Python всегда будет смотреть вверх type(instance).__dict__[attributename].__get__(instance, type(instance))и не буду использовать instance.__dict__ искать экземпляр-переопределение.

Вот пример использования надуманного Descriptor класс и свойство (дескриптор с __get__ и __set__:

>>> class Descriptor(object):
...     def __init__(self, name):
...         self.name = name
...     def __get__(self, instance, cls):
...         print 'Getting %s, with instance %r, class %r' % (self.name, instance, cls)
... 
>>> class Foo(object):
...     _spam = 'eggs'
...     @property
...     def spam(self):
...         return self._spam
...     @spam.setter
...     def spam(self, val):
...         self._spam = val
... 
>>> Foo().spam
'eggs'
>>> foo = Foo()
>>> foo.__dict__['spam'] = Descriptor('Override')
>>> foo.spam
'eggs'

Как видите, хотя я добавляю spam запись в инстансе __dict__полностью игнорируется и Foo.spam свойство используется до сих пор. Python игнорирует экземпляр __dict__ поскольку spam свойство определяет оба __get__ и __set__,

Если вы используете дескриптор, который не определяет __set__ переопределение работает (но это __get__ не называется:

>>> class Foo(object):
...     desc = Descriptor('Class-stored descriptor')
... 
>>> Foo.desc
Getting Class-stored descriptor, with instance None, class <class '__main__.Foo'>
>>> Foo().desc
Getting Class-stored descriptor, with instance <__main__.Foo object at 0x1018df510>, class <class '__main__.Foo'>
>>> foo = Foo()
>>> foo.__dict__['desc'] = Descriptor('Instance-stored descriptor')
>>> foo.desc
<__main__.Descriptor object at 0x1018df1d0>
Другие вопросы по тегам