有什么区别:

class Child(SomeBaseClass):
    def __init__(self):
        super(Child, self).__init__()

and:

class Child(SomeBaseClass):
    def __init__(self):
        SomeBaseClass.__init__(self)

我看到super在只有单一继承的类中被大量使用。我可以理解为什么在多重继承中使用它,但不清楚在这种情况下使用它的优势是什么。


当前回答

简单来说就是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分钟的视频。

其他回答

所有这些不都假定基类是一个新型的类吗?

class A:
    def __init__(self):
        print("A.__init__()")

class B(A):
    def __init__(self):
        print("B.__init__()")
        super(B, self).__init__()

将不能在python2中工作。类A必须是new-style,即:类A(对象)

考虑下面的代码:

class X():
    def __init__(self):
        print("X")

class Y(X):
    def __init__(self):
        # X.__init__(self)
        super(Y, self).__init__()
        print("Y")

class P(X):
    def __init__(self):
        super(P, self).__init__()
        print("P")

class Q(Y, P):
    def __init__(self):
        super(Q, self).__init__()
        print("Q")

Q()

如果将Y的构造函数更改为X.__init__,你将得到:

X
Y
Q

但是使用super(Y, self).__init__(),你会得到:

X
P
Y
Q

P或Q甚至可能涉及到另一个文件,当你写X和Y时,你不知道,所以基本上,当你写类Y(X)时,你不知道super(Child, self)会引用什么,甚至Y的签名也像Y(X)一样简单。这就是为什么超级可能是更好的选择。

简单来说就是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()在单继承中的好处是微乎其微的——大多数情况下,您不必将基类的名称硬编码到每个使用其父方法的方法中。

然而,如果没有super(),几乎不可能使用多重继承。这包括常见的习惯用法,如mixin、接口、抽象类等。这将扩展到稍后扩展您的代码。如果有人后来想要编写一个扩展Child和mixin的类,他们的代码将无法正常工作。

class Child(SomeBaseClass):
    def __init__(self):
        SomeBaseClass.__init__(self)

这很容易理解。

class Child(SomeBaseClass):
    def __init__(self):
        super(Child, self).__init__()

如果你使用super(Child,self)会发生什么?

当创建子实例时,它的MRO(方法解析顺序)是基于继承的(Child, SomeBaseClass, object)顺序。(假设SomeBaseClass除了默认对象之外没有其他父对象)

通过在self实例的MRO中传递Child、self、super搜索,并返回Child的next代理对象,在本例中是SomeBaseClass,该对象随后调用SomeBaseClass的__init__方法。换句话说,如果它是super(SomeBaseClass,self) super返回的代理对象将是object

对于多继承,MRO可以包含许多类,所以基本上super可以让您决定从MRO中的哪个位置开始搜索。