一个关于C3的例子
an example about C3
我从github那里得到了关于MRO和C3的代码,最后三行我不太明白,super().foo(), super(B ,self).foo()和super(C,self).foo() in python3.x,代码如下:
class A(object):
def foo(self):
print('foo of A')
class B(A):
pass
class C(A):
def foo(self):
print('foo fo C')
class D(B, C):
pass
class E(D):
def foo(self):
print('foo in E')
super().foo()
super(B, self).foo()
super(C, self).foo()
if __name__ == '__main__':
d = D()
d.foo()
e = E()
e.foo()
预期和实际结果如下:
foo fo C
foo in E
foo fo C
foo fo C
foo of A
首先,Python3中的形式super()
与super(<CurrentClass>, self)
其实是一回事,其中Python编译器provides enough information for super()
to determine what the correct class to use is。所以在E.foo()
中,super().foo()
可以读作super(E, self).foo()
。
要了解发生了什么,您需要查看 class.__mro__
attribute:
This attribute is a tuple of classes that are considered when looking for base classes during method resolution.
正是这个元组向您展示了 C3 方法解析顺序 对于任何给定的 class 层次结构。对于您的 class E
,该顺序是:
>>> E.__mro__
(<class '__main__.E'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
>>> for cls in E.__mro__: # print out just the names, for easier readability.
... print(cls.__name__)
...
E
D
B
C
A
object
super()
对象的所有内容都基于 classes 的有序序列。来电
super(SomeClass, self).foo()
导致以下一系列步骤:
super()
对象检索 self.__mro__
元组。
super()
在该元组中找到 SomeClass
class 的索引。
- 访问
super()
对象上的 foo
属性会触发对 class 的搜索,该 class 在 MRO 上具有 foo
属性,开始在 SomeClass
索引 . 之后的下一个索引处
- 如果以这种方式找到的属性是 descriptor object,则将以这种方式找到的属性绑定到
self
。函数是描述符,绑定产生绑定方法,调用方法时Python就是这样传入self
引用的。
表示为简化的 Python 代码,忽略边缘情况和 super()
的其他用途,看起来像:
class Super:
def __init__(self, type_, obj_or_type):
self.mro = obj_or_type.__mro__
self.idx = self.mro.index(type_) + 1
self.obj_or_type = obj_or_type
def __getattr__(self, name):
for cls in self.mro[self.idx:]:
attrs = vars(cls)
if name in attrs:
result = attrs[name]
if hasattr(result, '__get__'):
result = result.__get__(obj_or_type, type(self.obj_or_type))
return result
raise AttributeError(name)
结合这两条信息,您可以看到调用 e.foo()
:
时会发生什么
print('foo in E')
被执行,导致 E 中的 foo
super().foo()
被执行,实际上与 super(E, self).foo()
相同。
- 搜索MRO,从下一个索引过去
E
开始,所以在D
(没有foo
属性),移动到 B
(没有 foo
属性),然后是 C
(找到属性)。返回 C.foo
,绑定到 self
。
C.foo(self)
被调用,导致 foo fo C
super(B, self).foo()
被执行。
- 搜索 MRO,从下一个索引 过去
B
开始,所以在 C
(找到属性)。返回 C.foo
,绑定到 self
。
C.foo(self)
被调用,导致 foo fo C
super(C, self).foo()
被执行。
- 搜索 MRO,从下一个索引 过去
C
开始,所以在 A
(找到属性)。返回 A.foo
,绑定到 self
。
A.foo(self)
被调用,导致 A
的 foo
我从github那里得到了关于MRO和C3的代码,最后三行我不太明白,super().foo(), super(B ,self).foo()和super(C,self).foo() in python3.x,代码如下:
class A(object):
def foo(self):
print('foo of A')
class B(A):
pass
class C(A):
def foo(self):
print('foo fo C')
class D(B, C):
pass
class E(D):
def foo(self):
print('foo in E')
super().foo()
super(B, self).foo()
super(C, self).foo()
if __name__ == '__main__':
d = D()
d.foo()
e = E()
e.foo()
预期和实际结果如下:
foo fo C
foo in E
foo fo C
foo fo C
foo of A
首先,Python3中的形式super()
与super(<CurrentClass>, self)
其实是一回事,其中Python编译器provides enough information for super()
to determine what the correct class to use is。所以在E.foo()
中,super().foo()
可以读作super(E, self).foo()
。
要了解发生了什么,您需要查看 class.__mro__
attribute:
This attribute is a tuple of classes that are considered when looking for base classes during method resolution.
正是这个元组向您展示了 C3 方法解析顺序 对于任何给定的 class 层次结构。对于您的 class E
,该顺序是:
>>> E.__mro__
(<class '__main__.E'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
>>> for cls in E.__mro__: # print out just the names, for easier readability.
... print(cls.__name__)
...
E
D
B
C
A
object
super()
对象的所有内容都基于 classes 的有序序列。来电
super(SomeClass, self).foo()
导致以下一系列步骤:
super()
对象检索self.__mro__
元组。super()
在该元组中找到SomeClass
class 的索引。- 访问
super()
对象上的foo
属性会触发对 class 的搜索,该 class 在 MRO 上具有foo
属性,开始在SomeClass
索引 . 之后的下一个索引处
- 如果以这种方式找到的属性是 descriptor object,则将以这种方式找到的属性绑定到
self
。函数是描述符,绑定产生绑定方法,调用方法时Python就是这样传入self
引用的。
表示为简化的 Python 代码,忽略边缘情况和 super()
的其他用途,看起来像:
class Super:
def __init__(self, type_, obj_or_type):
self.mro = obj_or_type.__mro__
self.idx = self.mro.index(type_) + 1
self.obj_or_type = obj_or_type
def __getattr__(self, name):
for cls in self.mro[self.idx:]:
attrs = vars(cls)
if name in attrs:
result = attrs[name]
if hasattr(result, '__get__'):
result = result.__get__(obj_or_type, type(self.obj_or_type))
return result
raise AttributeError(name)
结合这两条信息,您可以看到调用 e.foo()
:
print('foo in E')
被执行,导致 E 中的 foo
super().foo()
被执行,实际上与super(E, self).foo()
相同。- 搜索MRO,从下一个索引过去
E
开始,所以在D
(没有foo
属性),移动到B
(没有foo
属性),然后是C
(找到属性)。返回C.foo
,绑定到self
。 C.foo(self)
被调用,导致 foo fo C
- 搜索MRO,从下一个索引过去
super(B, self).foo()
被执行。- 搜索 MRO,从下一个索引 过去
B
开始,所以在C
(找到属性)。返回C.foo
,绑定到self
。 C.foo(self)
被调用,导致 foo fo C
- 搜索 MRO,从下一个索引 过去
super(C, self).foo()
被执行。- 搜索 MRO,从下一个索引 过去
C
开始,所以在A
(找到属性)。返回A.foo
,绑定到self
。 A.foo(self)
被调用,导致 A
的 foo
- 搜索 MRO,从下一个索引 过去