我从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
答案 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}}索引。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()
相同。
super(E, self).foo()
开始,因此在E
(无D
属性)处,移至{{1 }}(没有foo
属性),然后是B
(找到属性)。返回foo
,绑定到C
。C.foo
被调用,导致 foo fo C self
被执行。
C.foo(self)
开始,因此搜索super(B, self).foo()
(找到属性)。返回B
,绑定到C
。C.foo
被调用,导致 foo fo C self
被执行。
C.foo(self)
开始,因此搜索super(C, self).foo()
(找到属性)。返回C
,绑定到A
。A.foo
被调用,导致A的 foo