关于Python超级多重继承的问题
Question on Python super multiple inheritance
我是新手Python,对超函数和多重继承真是一头雾水
这是玩具代码:
class A():
def __init__(self):
print('Call class A')
print('Leave class A')
class C(A):
def __init__(self):
print('Call class C')
A.__init__(self)
print('Leave class C')
class D(A):
def __init__(self):
print('Call class D')
#A.__init__(self)
super(D,self).__init__()
print('Leave class D')
class B(A):
def __init__(self):
print('Call class B')
super(B,self).__init__()
print('Leave class B')
class E(C,B,D):
def __init__(self):
print('Call class E')
B.__init__(self)
#C.__init__(self)
#D.__init__(self)
print('Leave class E')
则输出为:
Call class E
Call class B
Call class D
Call class A
Leave class A
Leave class D
Leave class B
Leave class E
(<class '__main__.E'>, <class '__main__.C'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.A'>, <class 'object'>)
其中 Class D 的 __init__
被调用。但是,如果我将 class E 更改为:
class E(B,C,D):
def __init__(self):
print('Call class E')
B.__init__(self)
#C.__init__(self)
#D.__init__(self)
print('Leave class E')
其中B,C,D顺序改变,则输出为:
Call class E
Call class B
Call class C
Call class A
Leave class A
Leave class C
Leave class B
Leave class E
(<class '__main__.E'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class '__main__.A'>, <class 'object'>)
那么classD的__init__
不会被调用,而是classC的,虽然class没有使用super
函数
有人知道吗:
1、在第一段代码中,为什么__init__
of class D也被调用了?
2、第二段代码为什么调用了class C的__init__
而没有调用class D的__init__
?
未能始终如一地使用 super
意味着您不能保证 MRO 将被正确执行。
在您的第一个示例中,在 E.__init__
中对 B.__init__
的显式调用可确保永远不会调用 C.__init__
,因为 B
在 C
之后MRO.
在第二个示例中,B
恰好是 E
之后的下一个 class,因此(还)没有任何问题。但随后在 C.__init__
中,您再次使用 A.__init__(self)
而不是 super(C, self).__init__()
,这意味着您直接从 C
跳到 A
,绕过了 D
应该是下一个。
在设计使用 super
的 class 层次结构 时(不仅仅是单个 class),您必须确保 every class使用super
来保证self
的runtime类型选择的MRO被遵循,而是而不是在编译时对父class方法进行硬编码调用。
正确的定义是
class A:
def __init__(self):
print('Call class A')
super().__init__()
print('Leave class A')
class C(A):
def __init__(self):
print('Call class C')
super().__init__()
print('Leave class C')
class D(A):
def __init__(self):
print('Call class D')
super().__init__()
print('Leave class D')
class B(A):
def __init__(self):
print('Call class B')
super().__init__()
print('Leave class B')
class E(C,B,D):
def __init__(self):
print('Call class E')
super().__init__(self)
print('Leave class E')
在 Python 3 中,一些编译器魔法在调用 super
时提供了 "default" 参数。例如,在 E.__init__
中,super().__init___()
等同于 super(C, self).__init__()
.
因为 self
的值(以及它的类型)在整个调用链中是不变的,所以每次使用 super()
都指向 MRO 中的下一个 class type(self)
。在上面的示例中,这将产生输出
Call class E
Call class C
Call class B
Call class D
Call class A
Leave class A
Leave class D
Leave class B
Leave class C
Leave class E
如果您在 E
的定义中更改基 classes 的顺序,MRO(以及输出)将自动更新,而无需更改任何进一步的代码。
我是新手Python,对超函数和多重继承真是一头雾水
这是玩具代码:
class A():
def __init__(self):
print('Call class A')
print('Leave class A')
class C(A):
def __init__(self):
print('Call class C')
A.__init__(self)
print('Leave class C')
class D(A):
def __init__(self):
print('Call class D')
#A.__init__(self)
super(D,self).__init__()
print('Leave class D')
class B(A):
def __init__(self):
print('Call class B')
super(B,self).__init__()
print('Leave class B')
class E(C,B,D):
def __init__(self):
print('Call class E')
B.__init__(self)
#C.__init__(self)
#D.__init__(self)
print('Leave class E')
则输出为:
Call class E
Call class B
Call class D
Call class A
Leave class A
Leave class D
Leave class B
Leave class E
(<class '__main__.E'>, <class '__main__.C'>, <class '__main__.B'>, <class '__main__.D'>, <class '__main__.A'>, <class 'object'>)
其中 Class D 的 __init__
被调用。但是,如果我将 class E 更改为:
class E(B,C,D):
def __init__(self):
print('Call class E')
B.__init__(self)
#C.__init__(self)
#D.__init__(self)
print('Leave class E')
其中B,C,D顺序改变,则输出为:
Call class E
Call class B
Call class C
Call class A
Leave class A
Leave class C
Leave class B
Leave class E
(<class '__main__.E'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class '__main__.A'>, <class 'object'>)
那么classD的__init__
不会被调用,而是classC的,虽然class没有使用super
函数
有人知道吗:
1、在第一段代码中,为什么__init__
of class D也被调用了?
2、第二段代码为什么调用了class C的__init__
而没有调用class D的__init__
?
未能始终如一地使用 super
意味着您不能保证 MRO 将被正确执行。
在您的第一个示例中,在 E.__init__
中对 B.__init__
的显式调用可确保永远不会调用 C.__init__
,因为 B
在 C
之后MRO.
在第二个示例中,B
恰好是 E
之后的下一个 class,因此(还)没有任何问题。但随后在 C.__init__
中,您再次使用 A.__init__(self)
而不是 super(C, self).__init__()
,这意味着您直接从 C
跳到 A
,绕过了 D
应该是下一个。
在设计使用 super
的 class 层次结构 时(不仅仅是单个 class),您必须确保 every class使用super
来保证self
的runtime类型选择的MRO被遵循,而是而不是在编译时对父class方法进行硬编码调用。
正确的定义是
class A:
def __init__(self):
print('Call class A')
super().__init__()
print('Leave class A')
class C(A):
def __init__(self):
print('Call class C')
super().__init__()
print('Leave class C')
class D(A):
def __init__(self):
print('Call class D')
super().__init__()
print('Leave class D')
class B(A):
def __init__(self):
print('Call class B')
super().__init__()
print('Leave class B')
class E(C,B,D):
def __init__(self):
print('Call class E')
super().__init__(self)
print('Leave class E')
在 Python 3 中,一些编译器魔法在调用 super
时提供了 "default" 参数。例如,在 E.__init__
中,super().__init___()
等同于 super(C, self).__init__()
.
因为 self
的值(以及它的类型)在整个调用链中是不变的,所以每次使用 super()
都指向 MRO 中的下一个 class type(self)
。在上面的示例中,这将产生输出
Call class E
Call class C
Call class B
Call class D
Call class A
Leave class A
Leave class D
Leave class B
Leave class C
Leave class E
如果您在 E
的定义中更改基 classes 的顺序,MRO(以及输出)将自动更新,而无需更改任何进一步的代码。