python数据和非数据描述符

python数据和非数据描述符,python,descriptor,python-descriptors,Python,Descriptor,Python Descriptors,根据, 定义了\uuuu set\uuuu()和\uuu get\uuuu()的数据描述符始终覆盖实例字典中的重新定义 我理解这句话没有问题,但有人能为我澄清一下为什么会有这样的规定吗?毕竟,如果我想覆盖实例字典中的一个属性,我已经需要明确地这样做(inst.\uu dict\uuu[“attr”]=val),因为一个幼稚的inst.attr=val将调用描述符的\uu set\uu方法,而该方法(通常)不会覆盖实例字典中的属性 编辑:我明白发生了什么,我的问题是为什么要制定这样的规则。覆盖适用

根据,

定义了
\uuuu set\uuuu()
\uuu get\uuuu()
的数据描述符始终覆盖实例字典中的重新定义

我理解这句话没有问题,但有人能为我澄清一下为什么会有这样的规定吗?毕竟,如果我想覆盖实例字典中的一个属性,我已经需要明确地这样做(
inst.\uu dict\uuu[“attr”]=val
),因为一个幼稚的
inst.attr=val
将调用描述符的
\uu set\uu
方法,而该方法(通常)不会覆盖实例字典中的属性


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

覆盖适用于类
\uuuu dict\uuu
中的描述符

Python将始终查找
type(instance)。\uuuuu dict\uuuuu[attributename]。\uuuu get\uuuu(instance,type(instance))
,并且不会使用
instance.\uuuu dict\uuu
来搜索实例重写

下面是一个使用人工设计的
描述符
类和属性(这是一个带有
\uuuuu get\uuuuuuu
\uuuu set\uuuuuuu
的描述符)的示例:

>>> 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'
如您所见,即使我在实例
\uuuuu dict\uuuu
中添加了
spam
条目,它也被完全忽略,并且仍然使用
Foo.spam
属性。Python忽略了实例
\uuu dict\uuuuu
,因为
spam
属性定义了
\uu get\uuuu
\uu集

如果您使用的描述符未定义
\uuuuu set\uuuu
,则覆盖会起作用(但它的
\uuuu get\uuuu
不会被调用:

>>> 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>
>>类Foo(对象):
…desc=描述符('类存储描述符')
... 
>>>Foo.desc
获取类存储描述符,无实例,类
>>>Foo().desc
获取类存储描述符,带有实例、类
>>>foo=foo()
>>>foo.\uuuuu dict\uuui['desc']=描述符('实例存储描述符')
>>>foo.desc

以下是CPython 2.7.3的实现:和。顺序是数据描述符、实例属性、非数据描述符,最后(仅获取)一个类属性。是的,我已经理解了这一部分。我的问题更多的是关于这一规则的基本原理;也就是说,我永远不会“意外地”在实例中重写类的数据描述符(即,为此,我需要访问dict)那么,如果我真的想这么做,为什么不允许我这么做呢?@antony:这是一个简洁的决定,要获得更详细的解释,请参见;但它的缺点是,您不能覆盖实例
\uuuuuuu class\uuuuuuuuuu
中的静态属性,如
\uuuuuuuuuuu dict\uuuuuuuu
。仍然不相信(同样,我的观点是Python的方法通常是其中之一)“同意的成年人”和摆弄
\uuuu dict\uuuuu
应该会得到你想要的——如果我想在遵守描述符协议的同时动态更新属性,我可以使用
setattr
)但我想我不应该在这里讨论语言设计。相反,在我看来,实现的方法效率较低:现在必须检查数据描述符的类型dict,然后检查非描述符属性的实例dict,然后再次检查非数据描述符的类型dict。