python数据和非数据描述符 [英] python data and non-data descriptors

查看:237
本文介绍了python数据和非数据描述符的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

根据 Python的文档

定义了__set__()__get__()的数据描述符始终会覆盖实例字典中的重定义.

Data descriptors with __set__() and __get__() defined always override a redefinition in an instance dictionary.

我很理解这句话,但是有人可以为我澄清为什么有这样的规则吗?毕竟,如果要覆盖实例字典中的属性,我已经需要明确地做到这一点,因为朴素的inst.attr = val会调用描述符的__set__方法, (通常)不会覆盖实例字典中的属性.

I have no problem understanding this sentence, but can someone clarify for me why such a rule is in place? After all, if I want to override an attribute in an instance dictionary, I already need to do that explicitely (inst.__dict__["attr"] = val), as a naive inst.attr = val would call the descriptor's __set__ method, which would (usually) not override the attribute in the instance dictionary.

为了清楚起见,我了解发生了什么,我的问题是为什么要制定这样的规则.

edit: just to make it clear, I understand what is happening, my question is about why such a rule was put in place.

推荐答案

该替代适用于 class __dict__的一部分的描述符.

The override applies to descriptors that are part of the class __dict__.

Python将始终查找type(instance).__dict__[attributename].__get__(instance, type(instance)),并且将使用instance.__dict__搜索实例替代.

Python will always look up type(instance).__dict__[attributename].__get__(instance, type(instance)), and will not use instance.__dict__ to search for a instance-override.

以下是使用人为设计的Descriptor类和属性(这是具有__get____set__的描述符的示例):

Here is an example using a contrived Descriptor class and a property (which is a descriptor with a __get__ and 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'

如您所见,即使我在实例__dict__中添加了spam条目,它也被完全忽略,并且仍使用Foo.spam属性. Python忽略了实例__dict__,因为spam属性同时定义了__get____set__.

As you can see, even though I add a spam entry in the instance __dict__, it is completely ignored and the Foo.spam property is used still. Python is ignoring the instance __dict__ because the spam property defines both __get__ and a __set__.

如果您使用的定义了__set__的描述符,则覆盖有效(但不会调用它的__get__:

If you use a descriptor that doesn't define a __set__ the override works (but it's __get__ is not called:

>>> 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>

这篇关于python数据和非数据描述符的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆