在下面这个例子中,方法 m
课堂上 A
只被调用一次。
我理解这是一个功能,这是Pythonic的方式来解决这个问题,其中的 A
's m
方法会在这种类似钻石的继承方案中被调用两次(如果它是以天真的方式实现的)。
这一切在这里都有描述。https:/www.python-course.eupython3_multiple_inheritance.php
(1)但在幕后......他们是如何实现这种行为的,即该班的 A
's m
方法只被调用一次?简单地问:在执行过程中,哪一行被 "跳过"--是哪一行?#1
或行 # 2
?
谁能给我更多的启示?我从来没有认真使用过多重继承,因为我主要用Java编程。所以我真的很好奇这里的这个方案,更具体的说是对它背后的内部工作原理很好奇。
注意:我只是想了解一下Python中的大致工作原理,而不是真的了解这里的每一个微小的细节。
(2)如果我想(在这个同样的场景下,并且由于某些原因) A
's m
方法被调用两次 (或 N
次,取决于多少个基类的 D
我们有),同时还可以通过使用 super()
. 这可能吗?是否 super()
支持这样的操作模式?
(3) 這是否只是一棵樹或 DAG 访问算法,他们一直在跟踪哪个类的 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)。它是基于 C3超类线性化 算法。这被称为线性化,因为树结构被分解成线性顺序。可以使用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'>]`
请注意mro法从哪里来?D
> B
> C
> > > A
. 你相信的地方 super()
简单地调用当前作用域的父类--其实不然。 它是通过你的 对象的类MRO(即。D.mro()
)与当前的类(即 B
, C
...)来确定哪个是下一个要解析方法的类。
的 super()
实际上使用了两个参数,但是当调用零参数时 课内,它是隐式传递的。
还要注意的是,除了零参数的形式之外,
super()
不限于在方法内部使用。两参数形式准确地指定了参数,并做了相应的引用。零参数形式只在类定义内部使用,因为编译器会填写必要的细节,以正确检索被定义的类,以及访问普通方法的当前实例。
准确地说,在 B.m()
జజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజ super()
调用实际转化为。
super(B, x).m()
# because the self being passed at the time is instance of D, which is x
该调用在 D.mro()
来自 B
类上,实际上是 C
,不 A
正如你所想象的那样。 因此。C.m()
首先被称为,在它的内部, super(C, x).m()
决心 A.m()
而这就是所谓的。
之后,它又解析回了之后的 super()
内 C.m()
,回升到之后的 super()
内 B.m()
,并回升到 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())
结果就是:
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'>]
所以实际上,没有任何东西被调用两次或跳过。 你只是误解了MRO基于调用的范围解析的想法,在这个范围内 super()
是,相对于从的调用。初始对象.
这里还有一个有趣的小例子,可以更详细地演示MRO。
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'>]