我有使用超级继承和多重继承的代码。 该课程的结果是:
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的超级。A被执行了,那就可以了。然后我期望B继续执行,因此这意味着B被执行,最后D被执行。 但是,这当然是不正确的。为什么要输入C,因为在B中找到了go方法的定义,然后它不再在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()
答案 0 :(得分:1)
Raymond Hettinger(Python核心开发人员)here展示了PyCon上的精彩视频。
主要收获是,超级不会叫你的父母,它叫你的后代的祖先。因此,每当您调用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中执行了相反的操作。
There is also a blog by RH here也涵盖了相同的主题,如果您无法观看youtube。
答案 1 :(得分:0)
调用d.go()
时,每次对super
的调用都使用调用实例的MRO(在这种情况下,d
的MRO为D,B,C,A,对象。super
不一定 必然指向其静态出现的类的父级。
这在B.go
的定义中最明显。尽管B
的定义对C
一无所知,但其self
参数是对类型为D
的对象的引用,并且是D
中的下一个类B
之后的MRO是C
,而不是A
。
答案 2 :(得分:0)
除极少数情况下,我个人不经常使用继承并避免多重继承。
这就像人们期望的那样棘手。
如果您通过先打印然后调用super
稍微更改代码,我认为您会更好地理解事情的运作方式:
唯一真正的区别是,我先打印然后致电super
。
除此之外,我仅使用lazier python3语法(无需从object
显式继承,如果从方法中调用,则无需将参数传递给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
中寻找该方法
因此将首先调用D.go()
。
super(D, self).go()
调用的 D.go()
将在self.__class__.__mro__
的MRO中查找下一个条目。记住我们在D
,所以它看着B
,在那里它将找到一个go
方法并调用它。
现在,事情的表现与您期望的不同,go()
中的B
方法并没有像您期望的那样查看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!