A B
| | | |
C D E F
| | | |
G H
|
I
user@ubuntu:~/Documents/Python/oop_python$ cat tt.py
class A:
def call_me(self):
print("A")
class C(A):
def call_me(self):
super().call_me()
print("C")
class D(A):
def call_me(self):
super().call_me()
print("D")
class B:
def call_me(self):
print("B")
class E(B):
def call_me(self):
super().call_me()
print("E")
class F(B):
def call_me(self):
super().call_me()
print("F")
class G(C, D, E):
def call_me(self):
super().call_me()
print("G")
class H(F):
def call_me(self):
super().call_me()
print("H")
class I(G, H):
def call_me(self):
super().call_me()
print("I")
user@ubuntu:~/Documents/Python/oop_python$ python3.2 -i tt.py
>>> i = I()
>>> i.call_me()
A
D
C
G
I
问题>为什么不打印B
,E
,F
?
// updated based on comments from delnan
user@ubuntu:~/Documents/Python/oop_python$ cat tt.py
class BaseClass():
def call_me(self):
print("BaseClass")
pass
class A(BaseClass):
def call_me(self):
super().call_me()
print("A")
class C(A):
def call_me(self):
super().call_me()
print("C")
class D(A):
def call_me(self):
super().call_me()
print("D")
class B(BaseClass):
def call_me(self):
super().call_me()
print("B")
class E(B):
def call_me(self):
super().call_me()
print("E")
class F(B):
def call_me(self):
super().call_me()
print("F")
class G(C, D, E):
def call_me(self):
super().call_me()
print("G")
class H(F):
def call_me(self):
super().call_me()
print("H")
class I(G, H):
def call_me(self):
super().call_me()
print("I")
user@ubuntu:~/Documents/Python/oop_python$ python3.2 -i tt.py
>>> i = I()
>>> i.call_me()
BaseClass
B
F
H
E
A
D
C
G
I
答案 0 :(得分:6)
一个常见的误解是super()将调用所有超类方法。它不会。它只会调用其中一个。哪一个是由super()根据一些特定规则自动计算的。有时它所称的那个不是真正的超级班,而是兄弟姐妹。但是不能保证所有的都被调用,除非所有类都使用super()。
在这种情况下,A和B不会调用super。如果你把它添加到A,它实际上会调用“缺失”类,但是如果你把它添加到B你会得到一个错误,因为在这种特殊情况下,B将最终成为“最后”(或者第一个,取决于你如何看待它)。
如果你想使用super(),最好的解决方案是为A和B提供一个实现call_me的公共基类,但不调用super()。 (感谢德尔南的建议)。
但是,如果您知道类层次结构,则可以直接调用超类方法而不是使用super()。请注意,在上面的情况中,这并不意味着每个类必须直接调用它的每个基类。因此,如果您作为程序员无法完全控制类层次结构,例如编写库或mixin-classes,则无用。然后你必须使用super()。
答案 1 :(得分:1)
使用super的前提条件是类必须是 new-style 。
具有单继承的类层次结构,super可用于引用父类而不明确命名它们
第二个用例是在动态执行环境中支持协作多重继承。
所以,第二种情况是匹配你的第二个例子条件。在这种情况下,子类将执行bfs traverse以确保每次覆盖基类方法仅被调用一次。您的继承树可以按此顺序重写为衬垫(遵循 bfs遍历,从左到右)I G C D A E H F B BaseClass。
超级(式[,对象或类型])
它将返回一个代理对象,该方法将方法调用委托给父类或兄弟类的类型。在python 3.x中,你可以直接调用super(),它与super(currentClassName,self)相同。这将获得由bfs遍历生成的直接右超级兄弟类的代理。所以方法i.call_me()将被称为:
I.call_me - > G.call_me - > C.call_me - > D.call_me - > A.call_me - > E.call_me - > H.call_me - > F.call_me - > B.call_me - > BaseClass.call_me
当你问为什么第一个例子没有打印B,E,F时,因为继承图不是“菱形图”,这意味着A.call_me B.call_me是不同的方法。所以python只选择一个继承分支。
希望这有用。您还可以查看python class doc了解更多详情