关于 C3 的示例



我从 github 得到了以下关于 MRO 和 C3 的代码,我不太明白最后三行,以及 python3.x 中 super().foo()、super(B,self).foo() 和 super(C,self).foo() 之间的区别,代码如下:

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    

首先,Python 3 中super()的形式实际上与super(<CurrentClass>, self)相同,其中 Python 编译器为super()提供了足够的信息来确定要使用的正确类是什么。所以在E.foo()super().foo()可以读作super(E, self).foo()

要了解发生了什么,您需要查看class.__mro__属性:

此属性是在方法解析期间查找基类时考虑的类元组。

正是这个元组向您展示了任何给定类层次结构的 C3方法解析顺序。对于您的类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()对象的所有内容都基于该有序类序列。电话会议

super(SomeClass, self).foo()

结果是以下一系列步骤:

  • super()对象检索self.__mro__元组。
  • super()在该元组中查找SomeClass类的索引。
  • 访问super()对象上的foo属性会触发对在 MRO 上具有foo属性的类的搜索,从SomeClass索引之后的下一个索引开始
  • 如果以这种方式找到的属性
  • 是描述符对象,则将以这种方式找到的属性绑定到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()
    • 过去C下一个索引开始搜索 MRO,因此从A(找到属性)开始。 返回A.foo,绑定到self
    • 调用A.foo(self),导致A 的 foo

相关内容

  • 没有找到相关文章

最新更新