Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/320.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python MRO—在多重继承中使用super_Python_Python 3.x_Super_Method Resolution Order - Fatal编程技术网

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!