Python's super() working?
我有一个这样的程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| class A():
def go(self):
print("A")
class B(A):
def go(self):
super().go()
print("B")
class C(A):
def go(self):
super().go()
print("C")
class D(A):
def go(self):
super().go()
print("D")
class E(B, C, D):
def go(self):
super().go()
print("E")
a = A()
b = B()
c = C()
d = D()
e = E()
print(e.go()) |
以下是输出:
号
我很好奇super()的工作流程,它是如何在b之前打印d、c的,为什么最后没有打印出来?一个详细的解释将是非常感谢。
- 你读过关于这个的现有资源吗?例如,stackoverflow.com/q/3277367/3001761。你还不明白什么?
- @cricket_007因为它是A后面的MRO中的下一个,所以你把mix-in放在实际的基类之前(参见stackoverflow.com/q/10018757/3001761)。
- 参见Raymond Hettinger的优秀博客文章,super-considered-super,rhettinger.wordpress.com/2011/05/26/super-considered-super和pycon 2015的谈话:youtube.com/watch?V=Eioglterpeo.您可以看到顺序d、c、b,因为这就是Python的方法解析顺序(MRO)的工作原理。
- @乔恩,我没想到init没有定义,只运行了e.go()。
- 我以为我理解了super的工作原理,然后这个问题来了,证明我错了。是时候再次像瘟疫一样避开以东王了。
如果调用help(e),则可以看到方法解析顺序:
1 2 3 4 5 6 7 8 9 10
| >>> e = E()
>>> help(e)
class E(B, C, D)
| Method resolution order:
| E
| B
| C
| D
| A
| builtins.object |
由于您首先调用super,然后调用print,输出将完全是反转的mro:
号
如果您在super呼叫之前拥有print,它将遵循MRO:
但是,E.go没有返回任何内容(return None是隐式的,如果之前没有其他return,那么它将在调用所有方法之后打印None。
- 是的,我理解MRO部分。但是B不应该在A之后打印,因为B已经完成了它的super()调用,现在它应该打印自己的部分了吗?
- @即使遗传不是线性的,MRO也总是线性的。所以当你使用super()时,它总是沿着MRO。
- @Anmolgulati问题是,python神奇地将C和D插入到B和A之间。在我看来,这是一个糟糕的设计选择。
- @Rawing好吧,你可以认为这是一个糟糕的设计选择,但是这样你就可以将"依赖注入"内置到基本继承中。您不需要像使用其他语言那样依赖框架来处理它。但有时会让人困惑——我总是需要检查help以确定继承是否按预期工作:)如果您不想困惑:避免多重继承-单一继承很容易理解。
- @小姐,请你再解释一下好吗?谢谢。
- @mseift-->"即使继承不是线性的,MRO也始终是线性的。所以当你使用super()时,它总是沿着mro"。这部分。
- @一旦调用方法python,Anmolgulati就会查看所调用类的mro。然后,MRO是固定的——它不会查看单个类的MRO。它只遵循您调用方法的类的MRO。对于钻石继承,记住MRO大致上是:兄弟姐妹优先(B、C和D——父母最后(A)。
- @感谢:—)