python数据和非数据描述符

时间:2012-10-22 07:59:57

标签: python descriptor python-descriptors

根据Python's documentation

  

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

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

编辑:为了说清楚,我明白发生了什么,我的问题是为什么要制定这样的规则。

1 个答案:

答案 0 :(得分:9)

覆盖适用于属于 __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>