我有这段代码,其中使用了超级继承和多重继承。该类的结果是:
go A go!
go C go!
go B go!
go D go!
虽然我期待:
go A go!
go B go!
go D go!
根据我的理解:D因为MRO而调用B类,因为go是在B中实现的。B类调用其父级A的super。A被执行了,这没关系。然后我希望B继续执行,所以这意味着B被执行,最后D被执行。但这当然是不对的。为什么它进入C,因为go方法的定义是在B中找到的,然后它就不应该再在C中搜索了。这就是MRO的工作原理。它在头等舱找到了,不应该再搜索了。完全困惑:(
class A(object):
def go(self):
print("go A go!")
class B(A):
def go(self):
super(B, self).go()
print("go B go!")
class C(A):
def go(self):
super(C, self).go()
print("go C go!")
class D(B,C):
def go(self):
super(D, self).go()
print("go D go!")
a = A()
b = B()
c = C()
d = D()
d.go()
这里有Raymond Hettinger(python核心开发人员(的PyCon的精彩视频。
主要的收获是super不叫你的父母,而是叫你后代的祖先。因此,每当您调用super
时,它都会返回到您实际调用方法的实例,并在MRO中查找下一个类型(即使有多重继承,这也是一个有保证的顺序,这也是class D(B,C)
与class D(C, B)
不同的原因(。
在您的情况下,D的MRO是(D,B,C,A(。当D.go
调用super时,它调用B.go
。当它调用super时,它仍在使用D的MRO,因此它移动到下一个类型,在您的情况下,C反过来调用A。最终结果是,您的打印语句在D的MRO中被反向执行。
这里还有RH的博客,如果你不能看youtube,它也涵盖了同样的主题。
当您调用d.go()
时,对super
的每次调用都使用调用实例的MRO(在这种情况下,MRO为D、B、C、A的d
,object。super
不一定是指静态出现的类的父级。
这一点在CCD_ 10的定义中最为明显。尽管B
的定义对C
一无所知,但其self
参数是对D
类型对象的引用,并且D
的MRO中B
之后的下一个类是C
,而不是A
。
我个人不经常使用继承,并避免多重继承,除非在极少数情况下。
正如人们所期望的那样,这更为棘手。
我认为,如果你先打印代码,然后调用super
:,稍微改变一下代码,你会更好地理解事情是如何工作的
唯一真正的区别是,我先打印,然后调用super
。除此之外,我使用了更懒惰的python3纯语法(无需显式继承object
,如果从方法中调用,则无需将params传递给super()
,它们将自动正确填充(,但这不会改变任何内容。
class A:
def go(self):
print("go A go!")
class B(A):
def go(self):
print("go B go!")
super().go()
class C(A):
def go(self):
print("go C go!")
super().go()
class D(B,C):
def go(self):
print("go D go!")
super().go()
b = B()
print(b.__class__)
print(b.__class__.__mro__)
d = D()
print(d.__class__)
print(d.__class__.__mro__)
d.go()
因此,您首先看到的是b
和d
的类和MRO,这并不奇怪。
如果D
有一个方法,它将被调用,如果它没有在B
中查找该方法,如果没有在C
中,如果没有A
中
因此CCD_ 29将首先被调用。
从D.go()
调用的super(D, self).go()
将在self.__class__.__mro__
的MRO中查找下一个条目。请记住,我们在D
,所以它会查看B
,在那里它会找到一个go
方法并调用它。
现在,事情的表现与您预期的不同,B
中的go()
方法并不像您预期的那样查看B
的MRO,它继续查看self.__class__
的MRO中的下一个条目,即C
,而不是您预期的A
,因为self.__class__
当然仍然是D
希望这有助于理解。
上述脚本的输出将是:
<class '__main__.B'>
(<class '__main__.B'>, <class '__main__.A'>, <class 'object'>)
<class '__main__.D'>
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
go D go!
go B go!
go C go!
go A go!