Sir*_*sto 5 python descriptor python-3.x python-descriptors
我一直在Descriptor HowTo Guide 中阅读有关描述符的内容,但我对这句话感到困惑:
如果实例的字典有一个与数据描述符同名的条目,则数据描述符优先。
字典如何包含两个具有相同名称的项目(一个普通条目和一个数据描述符)?或者作为描述符的属性没有存储在__dict__?
数据描述符位于类命名空间中,而实例属性位于实例命名空间(so instance.__dict__)中。这是两个独立的字典,所以这里没有冲突。
因此,对于foo实例上名称的任何给定属性查找bar,Python 还会按以下顺序查看它的类(type(bar),C如下命名):
C.foo是抬头。如果是数据描述符,则查找结束。C.foo.__get__(bar, C)被退回。否则,Python 会为第 3 步存储这个结果(没有必要查找两次)。
如果C.foo不存在或者是一个常规属性,那么 Python 会查找bar.__dict__['foo']. 如果存在,则返回。请注意,如果C.foo是数据描述符,则永远不会到达此部分!
如果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)