Python MRO-在多重继承中使用super



我有这段代码,其中使用了超级继承和多重继承。该类的结果是:

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()

因此,您首先看到的是bd的类和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!

相关内容

  • 没有找到相关文章

最新更新