Python 属性和描述符

Sir*_*sto 5 python descriptor python-3.x python-descriptors

我一直在Descriptor HowTo Guide 中阅读有关描述符的内容,但我对这句话感到困惑:

如果实例的字典有一个与数据描述符同名的条目,则数据描述符优先。

字典如何包含两个具有相同名称的项目(一个普通条目和一个数据描述符)?或者作为描述符的属性没有存储在__dict__?

Mar*_*ers 6

数据描述符位于命名空间中,而实例属性位于实例命名空间(so instance.__dict__)中。这是两个独立的字典,所以这里没有冲突。

因此,对于foo实例上名称的任何给定属性查找bar,Python 还会按以下顺序查看它的类(type(bar)C如下命名):

  1. C.foo是抬头。如果是数据描述符,则查找结束。C.foo.__get__(bar, C)被退回。否则,Python 会为第 3 步存储这个结果(没有必要查找两次)。

  2. 如果C.foo不存在或者是一个常规属性,那么 Python 会查找bar.__dict__['foo']. 如果存在,则返回。请注意,如果C.foo是数据描述符,则永远不会到达此部分!

  3. 如果bar.__dict__['foo']不存在,但C.foo存在,则C.foo使用。如果C.foo是(非数据)描述符,C.foo.__get__(bar, C)则返回。

(请注意,这C.foo确实是C.__dict__['foo'],但为了简单起见,我忽略了上面对类的描述符访问)。

也许一个具体的例子会有所帮助;这里有两个描述符,一个是数据描述符(有__set__方法),另一个不是数据描述符:

>>> class DataDesc(object):
...     def __get__(self, inst, type_):
...         print('Accessed the data descriptor')
...         return 'datadesc value'
...     def __set__(self, inst, value):
...         pass   # just here to make this a data descriptor
...
>>> class OtherDesc(object):
...     def __get__(self, inst, type_):
...         print('Accessed the other, non-data descriptor')
...         return 'otherdesc value'
...
>>> class C(object):
...     def __init__(self):
...         # set two instance attributes, direct access to not
...         # trigger descriptors
...         self.__dict__.update({
...             'datadesc': 'instance value for datadesc',
...             'otherdesc': 'instance value for otherdesc',
...         })
...     datadesc = DataDesc()
...     otherdesc = OtherDesc()
...
>>> bar = C()
>>> bar.otherdesc  # non-data descriptor, the instance wins
'instance value for otherdesc'
>>> bar.datadesc  # data descriptor, the descriptor wins
Accessed the data descriptor
'datadesc value'
Run Code Online (Sandbox Code Playgroud)