菱形问题-多重继承python-方法只调用一次-但如何调用?

菱形问题-多重继承python-方法只调用一次-但如何调用?,python,python-3.x,multiple-inheritance,Python,Python 3.x,Multiple Inheritance,在下面的示例中,类A上的方法m只调用一次 我知道这是一个特性,这是一种python方法,可以解决在这个菱形继承场景中,a的m方法会被调用两次的问题(如果它是以天真的方式实现的) 这里介绍了所有这些: (1) 但是在引擎盖下。。。他们是如何实现这种行为的,即类A的m方法只被调用一次 简单地问:哪一行在执行过程中被“跳过”——是第1行还是第2行 有人能解释一下吗? 我从未认真使用过多重继承,因为我主要用Java编程。所以我真的很好奇这个场景,更具体地说是它背后的内部运作 注意:我只是想了解Pyth

在下面的示例中,类
A
上的方法
m
只调用一次

我知道这是一个特性,这是一种python方法,可以解决在这个菱形继承场景中,
a
m
方法会被调用两次的问题(如果它是以天真的方式实现的)

这里介绍了所有这些:

(1) 但是在引擎盖下。。。他们是如何实现这种行为的,即类
A
m
方法只被调用一次
简单地问:哪一行在执行过程中被“跳过”——是第1行还是第2行

有人能解释一下吗?
我从未认真使用过多重继承,因为我主要用Java编程。所以我真的很好奇这个场景,更具体地说是它背后的内部运作

注意:我只是想了解Python中的工作原理,而不是真正理解这里的每个细节

(2) 如果我想(在同一个场景中,出于某种原因)调用
A
m
方法两次(或者
N
次,取决于
D
的基类的数量),同时仍然使用
super()
,该怎么办。这可能吗?
super()
是否支持这种操作模式

(3) 这仅仅是一些树或访问算法,它们跟踪哪个类的
m
方法已经被访问过,只是不访问它(调用它)两次?如果是这样的话,那么简单地说,我猜“#2”是跳过的那一行

class A:
    def m(self):
        print("m of A called")

class B(A):
    def m(self):
        print("m of B called")
        super().m() # 1 

class C(A):
    def m(self):
        print("m of C called")
        super().m()  # 2 

class D(B,C):
    def m(self):
        print("m of D called")
        super().m()


if (__name__ == '__main__'):
    x = D()
    x.m()

这与方法解析顺序有关,您链接的文章已经提供了一些见解(以及更多信息):

问题是超级函数是如何做出决定的。怎么 它是否决定必须使用哪个类?正如我们已经说过的那样 如上所述,它使用所谓的方法解析顺序(MRO)。它是 基于该算法。这就是所谓的 线性化,因为树结构被分解为线性 秩序。mro方法可用于创建此列表:

>>> from super_init import A,B,C,D`  
>>> D.mro() [<class 'super_init.D'>, <class 'super_init.B'>, <class 'super_init.C'>, <class 'super_init.A'>, <class 'object'>]`
该调用在
D.mro()
中从
B
类开始解析,它实际上是
C
,而不是您想象的
A
。因此,首先调用
C.m()
,在其中,
super(C,x).m()
解析为
A.m()
,然后调用

在此之后,它将解析回
C.m()
中的
super()
之后,将解析回
B.m()
中的
super()
之后,并将解析回
D.m()
。当您再添加几行时,很容易观察到这一点:

class A:
    def m(self):
        print("m of A called")

class B(A):
    def m(self):
        print("m of B called")
        print(super())
        super().m() # resolves to C.m        
        print('B.m is complete')

class C(A):
    def m(self):
        print("m of C called")
        print(super())
        super().m()  # resolves to A.m
        print('C.m is complete')

class D(B,C):
    def m(self):
        print("m of D called")  
        print(super())
        super().m() # resolves to B.m
        print('D.m is complete')

if (__name__ == '__main__'):
    x = D()
    x.m()
    print(D.mro())
其结果是:

结果:

#x.m()调用:
m of D呼叫
当前MRO:*D*>B>X>C>A>对象
c_只调用,调用c中的m
C的m被称为
当前MRO:D>B>X>*C*>A>对象
“super”对象没有属性“b_only”
我是一个被称为
当前MRO:D>B>X>C>*A*>对象
C.m.完成了
B的m被称为
当前MRO:D>*B*>X>C>A>对象
称为X的m
当前MRO:D>B>*X*>C>A>对象
只打了一个电话
X.m完成了
B.m.完成了
D.m.完成了
#D.mro()调用:
[, , , ]
#x2.m()调用:
称为X的m
当前MRO:*X*>对象
“super”对象没有属性“a_only”
X.m完成了
#X.mro()调用:
[, ]

对于第一个问题,我的理解是,
super()
检查类的方法解析顺序,可以通过调用对象上的
help()
来找到,并简单地选择下一行的方法。如果你想了解更多关于MRO计算的细节,我建议你阅读C3线性化。为了更直接地回答您的问题,1或2都不会被跳过
D.m()
调用
B.m()
哪个调用
C.m()
哪个调用
A.m()
。你能澄清一下“类A上的方法
m
只调用一次”是什么意思吗?所有
D.m
C.m
B.m
A.m
都被调用;不跳过#1和#2。如果该方法被“两次”调用,您希望发生什么情况?@Axe319 Oh。。。这就是它的工作原理吗?你写的这个简单的声明澄清了很多。谢谢你的链接太关于C3线性化。这是直截了当的。@Justlearnedit对我来说运行正常,这就是为什么我要问它。如果一个人刚刚学会了这一点,也许他应该更加谦虚:)我不确定我是否明白这一切。。。但我以后肯定会再读几遍。谢谢!我已经用当前的MRO更新了后面的示例,以显示
super()
解决了什么问题,也许这有助于理解发生了什么。
class A:
    def m(self):
        print("m of A called")

class B(A):
    def m(self):
        print("m of B called")
        print(super())
        super().m() # resolves to C.m        
        print('B.m is complete')

class C(A):
    def m(self):
        print("m of C called")
        print(super())
        super().m()  # resolves to A.m
        print('C.m is complete')

class D(B,C):
    def m(self):
        print("m of D called")  
        print(super())
        super().m() # resolves to B.m
        print('D.m is complete')

if (__name__ == '__main__'):
    x = D()
    x.m()
    print(D.mro())
m of D called
<super: <class 'D'>, <D object>>
m of B called
<super: <class 'B'>, <D object>>
m of C called
<super: <class 'C'>, <D object>>
m of A called
C.m is complete  # <-- notice how C.m is completed before B.m
B.m is complete
D.m is complete
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
def print_cur_mro(cls, obj):
    # helper function to show current MRO
    print(f"Current MRO: {' > '.join([f'*{m.__name__}*' if m.__name__ == cls.__name__ else m.__name__ for m in type(obj).mro()])}")

class X:
    def m(self):
        print('m of X called')
        print_cur_mro(X, self)
        try:
            super().a_only() # Resolves to A.a_only if called from D(), even though A is not in X inheritance
        except AttributeError as exc:
            # Resolves to AttributeError if not called from D()
            print(type(exc), exc)
        print('X.m is complete')

class A:
    def m(self):
        print("m of A called")
        print_cur_mro(A, self)

    def a_only(self):
        print('a_only called')

class B(X):
    def m(self):
        print("m of B called")
        print_cur_mro(B, self)
        super().m() # Resolves to X.m
        print('B.m is complete')

    def b_only(self):
        print('b_only called')

class C(A):
    def m(self):
        print("m of C called")
        print_cur_mro(C, self)
        try:
            super().b_only() # Resolves to AttributeError if called, since A.b_only doesn't exist if from D()
        except AttributeError as exc:
            print(type(exc), exc)
        super().m() # Resolves to A.m
        print('C.m is complete')

    def c_only(self):
        print('c_only called, calling m of C')
        C.m(self)

class D(B,C):
    def m(self):
        print("m of D called")
        print_cur_mro(D, self)
        super().c_only() # Resolves to C.c_only, since c_only doesn't exist in B or X.
        super().m() # Resolves to B.m
        print('D.m is complete')

if (__name__ == '__main__'):
    x = D()
    x.m()
    print(D.mro())
    x2 = X()
    x2.m()
    print(X.mro())
# x.m() call:
m of D called
Current MRO: *D* > B > X > C > A > object
c_only called, calling m of C
m of C called
Current MRO: D > B > X > *C* > A > object
<class 'AttributeError'> 'super' object has no attribute 'b_only'
m of A called
Current MRO: D > B > X > C > *A* > object
C.m is complete
m of B called
Current MRO: D > *B* > X > C > A > object
m of X called
Current MRO: D > B > *X* > C > A > object
a_only called
X.m is complete
B.m is complete
D.m is complete

# D.mro() call:
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.X'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

# x2.m() call:
m of X called
Current MRO: *X* > object
<class 'AttributeError'> 'super' object has no attribute 'a_only'
X.m is complete

# X.mro() call:
[<class '__main__.X'>, <class 'object'>]