关于C3的示例

时间:2019-02-18 22:20:20

标签: python python-3.x method-resolution-order

我从github上获得了有关MRO和C3的以下代码,但我不太了解最后三行,以及super()。foo(),super(B,self).foo( )和python3.x中的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    

1 个答案:

答案 0 :(得分:1)

首先,Python 3中的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

  

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

此元组向您显示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类的索引。
  • 访问foo对象上的super()属性会触发对MRO上具有foo属性的类的搜索,从{{之后的下一个索引开始1}}索引
  • 如果以此方式找到的属性是descriptor object,则将以此方式找到的属性绑定到SomeClass。函数是描述符,绑定会生成绑定的方法,这就是Python在调用方法时传递self引用的方式。

表示为简化的Python代码,它忽略了self的极端情况和其他用法,如下所示:

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()被执行,导致E中的 foo
  • print('foo in E')被执行,实际上与super().foo()相同。
    • 搜索MRO,从下一个索引 past super(E, self).foo()开始,因此在E(无D属性)处,移至{{1 }}(没有foo属性),然后是B(找到属性)。返回foo,绑定到C
    • C.foo被调用,导致 foo fo C
  • self被执行。
    • 搜索MRO,从下一个索引 past C.foo(self)开始,因此搜索super(B, self).foo()(找到属性)。返回B,绑定到C
    • C.foo被调用,导致 foo fo C
  • self被执行。
    • 搜索MRO,从下一个索引 past C.foo(self)开始,因此搜索super(C, self).foo()(找到属性)。返回C,绑定到A
    • A.foo被调用,导致A的 foo