菱形问题-多重继承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'>]