Python 类的 `__mro__` 属性从何而来?

pos*_*aki 5 python python-3.x

假设有一些类:

class Test():
    pass 
Run Code Online (Sandbox Code Playgroud)

(1)在 SO 和文档中的某处,我接下来阅读:

mro()在类实例化时调用,其结果存储在__mro__.

好的,这对我来说仍然很清楚,因为__mro__确实存储了一些东西:

Test.__mro__                                                         
Out[48]: (__main__.Test, object)
Run Code Online (Sandbox Code Playgroud)

再一次,我在某处读到了这个:

要查找属性名称 Python 搜索:
a) 搜索在 C 处找到__dict__的所有元类__mro____class__
b) 如果在步骤 a 中找到数据描述符,则调用它__get__() 并退出。
c) 否则,__dict__ 在 C 自己的类的 中调用描述符或返回值__mro__
d) 调用在步骤 a 中找到的非数据描述符。
e)否则,返回元类树值

我可以发现没有__mro__in Test.__dict__

'__mro__' in Test.__dict__                                           
Out[49]: False
Run Code Online (Sandbox Code Playgroud)

因此,根据e之前引用的条款,我想这 __mro__应该取自“元类树值”,因此取自type.__dict__

真的,还有__mro__type.__dict__

["mro:<method 'mro' of 'type' objects>",
"__mro__:<member '__mro__' of 'type' objects>"]
Run Code Online (Sandbox Code Playgroud)
  1. 那么上面 (1) 中提到的关于文档mro()存储在__mro__属性中的结果并不能真正以这种方式工作?

  2. <member '__mro__' of 'type' objects>结果如何(__main__.Test, object)

也许你可以展示一些源代码来理解当我打电话给Test.__mro__..

Mis*_*agi 4

“属性__mro__”是一个数据描述符,类似于property。描述符不是__mro__从 获取属性值__dict__,而是从另一个地方获取值或计算它。具体来说, a<member \'...\' of \'..\' objects>表示从 VM 内部位置 \xe2\x80\x93 获取值的描述符,这与所使用的机制__slots__相同。

\n
>>> class Bar:\n...     __slots__ = "foo",\n...\n>>> Bar.foo\n<member \'foo\' of \'Bar\' objects>\n>>> \'foo\' in Bar.__dict__\nTrue\n
Run Code Online (Sandbox Code Playgroud)\n

描述符被继承而不会重复,因此不会显式出现在子类上。

\n
>>> class Foo(Bar):\n...     __slots__ = ()\n...\n>>> Foo.foo\n<member \'foo\' of \'Bar\' objects>\n>>> \'foo\' in Foo.__dict__\nFalse\n
Run Code Online (Sandbox Code Playgroud)\n

这种数据描述符的精确工作member是由实现定义的。property然而,从逻辑上讲,它们的工作原理与使用内部存储相同:

\n
class FooBar:\n    def __init__(self, foo, bar):\n        # attributes stored internally\n        # the "_data" of a member is not visible\n        self._data = [foo, bar]\n\n    @property\n    def foo(self):\n        return self._data[0]\n\n    @foo.setter\n    def foo(self, value):\n        self._data[0] = value\n\n    @property\n    def bar(self):\n        return self._data[1]\n\n    @bar.setter\n    def bar(self, value):\n        self._data[1] = value\n
Run Code Online (Sandbox Code Playgroud)\n