Python MRO—在多重继承中使用super
我有一段使用超级继承和多重继承的代码。 课程结果如下:Python MRO—在多重继承中使用super,python,python-3.x,super,method-resolution-order,Python,Python 3.x,Super,Method Resolution Order,我有一段使用超级继承和多重继承的代码。 课程结果如下: 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被执行。 但这当然是不对的。既然在B中找到了go方法的定义,那么它为什么要输入C,而不应该再在C中搜索。这就是MRO的工作原理。它是在一等舱中找
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被执行。
但这当然是不对的。既然在B中找到了go方法的定义,那么它为什么要输入C,而不应该再在C中搜索。这就是MRO的工作原理。它是在一等舱中找到的,不应该再搜索了。完全困惑:(
调用d.go()
时,对super
的每次调用都使用调用实例的MRO(在本例中,d
的MRO为d、B、C、A、object)。super
不一定引用静态显示的类的父级
这在
B.go
的定义中最为明显。尽管B
的定义对C
一无所知,但它的self
参数是对D
类型的对象的引用,而D
的MRO中B
之后的下一个类是C
,而不是a
/p>有一个Raymond Hettinger(python核心开发人员)提供的PyCon优秀视频
主要的好处是super不会调用你的父母,它会调用你后代的祖先。因此,每当你调用super
,它都会返回到你实际调用方法的实例,并在MRO中查找下一个类型(这是一个有保证的顺序,即使有多重继承,为什么类D(B,C)
与D类(C、B)
不同
在您的例子中,D的MRO是(D,B,C,A)。当D.go
调用super时,它调用B.go
。当调用super时,它仍然使用D的MRO,因此它移动到下一种类型,在您的例子中,C反过来调用A。最终结果是,您的打印语句在D的MRO中被执行
如果你看不到youtube,它也会涉及相同的主题。我个人不经常使用继承,并且避免多重继承,除非在非常罕见的情况下 正如人们所预料的那样,它更为棘手 如果您先打印代码,然后调用
super
,稍微更改代码,我想您会更好地理解事情的工作原理:
唯一的区别是,我先打印,然后调用super
。
除此之外,我只使用了lazier python3语法(无需显式继承对象
,无需将参数传递给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.\uuuuu class.\uuuuuuu MRO.\uuuuuu
的MRO中查找下一个条目。记住我们在D
,所以它会在B
中找到一个go
方法并调用它
现在,事情的行为与您预期的不同之处在于,go()B
中的
方法并不像您期望的那样查看B
的MRO,它继续查看self的MRO中的下一个条目。它是C
,而不是A
,因为self.\uu 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!
(, )
(, , )
去吧,去吧!
去吧,去吧!
加油,加油!
加油!
我认为要搜索方法的类列表是在执行任何方法之前建立的。您似乎假设此列表是在执行方法时动态确定的。
<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!