Данные 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>