13

根据Python 的文档

__set__()带有和__get__()定义的数据描述符总是覆盖实例字典中的重新定义。

我理解这句话没有问题,但是有人可以为我澄清为什么会有这样的规则吗?毕竟,如果我想覆盖实例字典中的属性,我已经需要显式地执行此操作(inst.__dict__["attr"] = val),因为天真的inst.attr = val会调用描述符的__set__方法,这(通常)不会覆盖实例字典中的属性。

编辑:为了清楚起见,我了解正在发生的事情,我的问题是为什么要制定这样的规则。

4

1 回答 1

10

覆盖适用于属于 __dict__的描述符。

Python 将始终查找type(instance).__dict__[attributename].__get__(instance, type(instance)),并且不会用于instance.__dict__搜索实例覆盖。

这是一个使用人为Descriptor类和属性的示例(这是一个带有 a__get__和 a的描述符__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__和 a __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>
于 2012-10-22T08:09:51.037 回答