python 'super' 在多重继承中 - 意外的代码输出
python 'super' in multiple inheritance - unexpected code output
我对 python OOP 比较陌生。
尽管我对 JAVA OOP 有一些经验并且我知道方法 'super' 的含义,但当我有多个继承时,我很难理解它在 python 中是如何工作的(没有存在于 JAVA)
在挖掘找到一些答案后,我读到根据继承图,对于每个 class python 制定了一个方法解析顺序 (MRO) 以确定以什么顺序查找一个实例方法。
我还看到 MRO 由 "old style" 或 "new style" 决定,具体取决于我的 python 版本。
我有 python 3.7,所以我使用 "new style" 方法。
如果我没理解错的话,每次重写一个方法调用'super',python就会转到之后[=]出现的class中的方法40=] MRO 中的当前 class。
的确,当我运行以下代码时:
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(根据 "new style")的任何解释,将不胜感激!
问题是您的 classes 不是协同定义的。 A
和B
都认为已经引入了foo
,所以没必要调用super().foo
,因为各自认为会是最后一个class ] 在任何潜在的 MRO 中定义 foo
。 AB
证明事实并非如此。
当您调用 AB.foo
时,它做的第一件事就是调用 A.foo
。但是,A.foo
不使用 super
,因此链结束,并且 B.foo
永远不会被调用。
在正确设计的层次结构中,恰好 一个 class "introduces" 一个方法,负责通过不调用来终止链 super
.任何其他想要成为层次结构一部分的 class 负责调用 super
.
在你的A
/B
/AB
情况下,你有几个选择:
让 A
和 B
都继承自 FooBase
,并让它们从 [=13= 的实现中调用 super().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 OOP 比较陌生。 尽管我对 JAVA OOP 有一些经验并且我知道方法 'super' 的含义,但当我有多个继承时,我很难理解它在 python 中是如何工作的(没有存在于 JAVA)
在挖掘找到一些答案后,我读到根据继承图,对于每个 class python 制定了一个方法解析顺序 (MRO) 以确定以什么顺序查找一个实例方法。
我还看到 MRO 由 "old style" 或 "new style" 决定,具体取决于我的 python 版本。 我有 python 3.7,所以我使用 "new style" 方法。
如果我没理解错的话,每次重写一个方法调用'super',python就会转到之后[=]出现的class中的方法40=] MRO 中的当前 class。
的确,当我运行以下代码时:
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(根据 "new style")的任何解释,将不胜感激!
问题是您的 classes 不是协同定义的。 A
和B
都认为已经引入了foo
,所以没必要调用super().foo
,因为各自认为会是最后一个class ] 在任何潜在的 MRO 中定义 foo
。 AB
证明事实并非如此。
当您调用 AB.foo
时,它做的第一件事就是调用 A.foo
。但是,A.foo
不使用 super
,因此链结束,并且 B.foo
永远不会被调用。
在正确设计的层次结构中,恰好 一个 class "introduces" 一个方法,负责通过不调用来终止链 super
.任何其他想要成为层次结构一部分的 class 负责调用 super
.
在你的A
/B
/AB
情况下,你有几个选择:
让
A
和B
都继承自FooBase
,并让它们从 [=13= 的实现中调用super().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__
在合作继承设置中正常工作的更多建议,请参阅链接文章。