我对 python OOP 比较陌生。 虽然我有一些 JAVA OOP 经验并且我知道方法“super”的含义,但当我有多个继承(JAVA 中不存在)时,我很难理解它在 python 中是如何工作的
在挖掘找到一些答案后,我根据继承图读到,对于每个类,python 都制定了一个方法解析顺序 (MRO) 来确定以什么顺序查找实例方法。
我还读到 MRO 由“旧式”或“新式”决定,具体取决于我的 python 版本。 我有 python 3.7,所以我使用“新样式”方法。
如果我理解正确,每次重写一个方法并调用“super”时,python 都会转到 MRO 中当前类之后出现的类中的方法。
确实,当我运行以下代码时:
class A(object):
def go(self):
print("go A go!")
class B(A):
def go(self):
super(B, self).go()
print("go B go!")
class C(A):
def go(self):
super(C, self).go()
print("go C go!")
class D(B,C):
def go(self):
super(D, self).go()
print("go D go!")
if __name__ == "__main__":
d = D()
d.go()
print(D.__mro__)
我得到了输出:
go A go!
go C go!
go B go!
go D go!
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
到目前为止一切顺利,但是当我尝试运行以下代码时:
class A(object):
def foo(self):
print('this is A')
class B(object):
def foo(self):
print('this is B')
class AB(A,B):
def foo(self):
super(AB,self).foo()
print('this is AB')
if __name__ == '__main__':
x = AB()
x.foo()
print(AB.__mro__)
我得到了输出:
this is A
this is AB
(<class '__main__.AB'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
而不是我预期的输出:
this is B
this is A
this is AB
(<class '__main__.AB'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
所以显然我不明白发生了什么......
对于这种情况的任何解释,以及 python 如何准确地确定 MRO(根据“新样式”),将不胜感激!
最佳答案
问题是你的类不是协同定义的。 A
和B
都认为它引入了foo
,因此不需要调用super().foo
,因为每个人都认为这将是任何潜在 MRO 中定义 foo
的最后一个类。 AB
证明事实并非如此。
当您调用 AB.foo
时,它做的第一件事就是调用 A.foo
。但是,A.foo
不使用 super
,因此链结束,B.foo
永远不会被调用。
在正确设计的层次结构中,只有 一个 类“引入”了一个方法,并负责通过不调用 super
来终止链。任何其他想要成为层次结构一部分的类都负责调用 super
。
在您的 A
/B
/AB
案例中,您有几个选择:
A
和B
都继承自FooBase
,并分别调用super().foo ()
来自其foo
的实现。FooBase.foo
本身不调用super
。AB
不是直接从A
和B
继承,而是从其中一个或两个的包装器继承,其中包装器正确地实现了合作继承。 (有关详细信息,请参阅 Python's super() considered super!.。)例如,这里我们包装
A
并让B
作为foo
的基础:class A: def foo(self): print('this is A') class AWrapper: def __init__(self, **kwargs): super().__init__() self.a = A() def foo(self): super().foo() self.a.foo() class B(object): def foo(self): print('this is B') # Important: AWrapper must come first class AB(AWrapper, B): def foo(self): super().foo() print('this is AB') AB().foo()
请注意,如果 __init__
本身需要在 A
和 B
中定义,这将变得更加复杂;有关使 __init__
在合作继承设置中正常工作的更多建议,请参阅链接文章。
关于多重继承中的 python 'super' - 意外的代码输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56041198/