有什么区别:
class Child(SomeBaseClass):
def __init__(self):
super(Child, self).__init__()
and:
class Child(SomeBaseClass):
def __init__(self):
SomeBaseClass.__init__(self)
我看到super在只有单一继承的类中被大量使用。我可以理解为什么在多重继承中使用它,但不清楚在这种情况下使用它的优势是什么。
在多重继承的情况下,通常需要调用双亲的初始化式,而不仅仅是第一个。super()并不总是使用基类,而是在方法解析顺序(MRO)中查找下一个类,并将当前对象作为该类的实例返回。例如:
class Base(object):
def __init__(self):
print("initializing Base")
class ChildA(Base):
def __init__(self):
print("initializing ChildA")
Base.__init__(self)
class ChildB(Base):
def __init__(self):
print("initializing ChildB")
super().__init__()
class Grandchild(ChildA, ChildB):
def __init__(self):
print("initializing Grandchild")
super().__init__()
Grandchild()
结果
initializing Grandchild
initializing ChildA
initializing Base
用super().__init__()替换Base.__init__(self)会导致
initializing Grandchild
initializing ChildA
initializing ChildB
initializing Base
根据需要。
简单来说就是Super()
每个Python实例都有一个创建它的类。
Python中的每个类都有一个祖先类链。
使用super()委托的方法工作到实例类的链中的下一个祖先。
例子
这个小例子涵盖了所有有趣的情况:
class A:
def m(self):
print('A')
class B(A):
def m(self):
print('B start')
super().m()
print('B end')
class C(A):
def m(self):
print('C start')
super().m()
print('C end')
class D(B, C):
def m(self):
print('D start')
super().m()
print('D end')
调用的确切顺序由调用该方法的实例决定:
>>> a = A()
>>> b = B()
>>> c = C()
>>> d = D()
例如a,没有super调用:
>>> a.m()
A
例如实例b,祖先链为b -> A ->对象:
>>> type(b).__mro__
(<class '__main__.B'>, <class '__main__.A'>, <class 'object'>)
>>> b.m()
B start
A
B end
例如c,父链为c -> A ->对象:
>>> type(c).__mro__
(<class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
>>> c.m()
C start
A
C end
例如,祖先链d更有趣d -> B -> C -> A ->对象(mro代表方法解析顺序):
>>> type(d).__mro__
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
>>> d.m()
D start
B start
C start
A
C end
B end
D end
更多的信息
回答了“super在Python中做什么?”的问题后,下一个问题是如何有效地使用它。请看这个循序渐进的教程或者这个45分钟的视频。
我曾经使用过super(),并且认识到我们可以改变调用顺序。
例如,我们有下一个层次结构:
A
/ \
B C
\ /
D
在这种情况下,D的MRO将是(仅适用于Python 3):
In [26]: D.__mro__
Out[26]: (__main__.D, __main__.B, __main__.C, __main__.A, object)
让我们创建一个类,其中super()在方法执行后调用。
In [23]: class A(object): # or with Python 3 can define class A:
...: def __init__(self):
...: print("I'm from A")
...:
...: class B(A):
...: def __init__(self):
...: print("I'm from B")
...: super().__init__()
...:
...: class C(A):
...: def __init__(self):
...: print("I'm from C")
...: super().__init__()
...:
...: class D(B, C):
...: def __init__(self):
...: print("I'm from D")
...: super().__init__()
...: d = D()
...:
I'm from D
I'm from B
I'm from C
I'm from A
A
/ ⇖
B ⇒ C
⇖ /
D
所以我们可以看到分辨率顺序和MRO是一样的。但是当我们在方法的开头调用super()时:
In [21]: class A(object): # or class A:
...: def __init__(self):
...: print("I'm from A")
...:
...: class B(A):
...: def __init__(self):
...: super().__init__() # or super(B, self).__init_()
...: print("I'm from B")
...:
...: class C(A):
...: def __init__(self):
...: super().__init__()
...: print("I'm from C")
...:
...: class D(B, C):
...: def __init__(self):
...: super().__init__()
...: print("I'm from D")
...: d = D()
...:
I'm from A
I'm from C
I'm from B
I'm from D
我们有一个不同的顺序,它颠倒了MRO元组的顺序。
A
/ ⇘
B ⇐ C
⇘ /
D
对于额外的阅读,我推荐下面的答案:
带有super的C3线性化示例(一个大层次结构)
新旧样式类之间的重要行为变化
关于新式课程的内幕