Python 超级初始化与父级初始化__

Python 超级初始化与父级初始化__,python,python-2.7,inheritance,Python,Python 2.7,Inheritance,Python子类可以通过调用或不调用super()来初始化,如下所示 class Parent(object): ... class Child(Parent): def __init__(self): super(Child, self).__init__() class Child(Parent): def __init__(self): Parent.__init__(self) 这些案例之间的区别是什么?一个案例通常比另

Python子类可以通过调用或不调用
super()
来初始化,如下所示

class Parent(object):
    ...

class Child(Parent):

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


class Child(Parent):

    def __init__(self):
        Parent.__init__(self)

这些案例之间的区别是什么?一个案例通常比另一个更可取吗?

super的目的是处理继承钻石。如果班级 继承结构只使用单个继承,然后使用super()将 导致与显式调用“父”类相同的调用

以这颗钻石为例:

class A(object):
    def __init__(self):
        print('Running A.__init__')
        super(A,self).__init__()

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

class C(A):
    def __init__(self):
        print('Running C.__init__')
        super(C,self).__init__()

class D(B,C):
    def __init__(self):
        print('Running D.__init__')
        super(D,self).__init__()

foo = D()
哪张照片

Running D.__init__
Running B.__init__
Running C.__init__
Running A.__init__
而如果我们将
B
更改为
B2
,并使用对父级
\uuuu init\uuuu
的显式调用:

class B2(A):
    def __init__(self):
        print('Running B.__init__')        
        A.__init__(self) 

class D2(B2,C):
    def __init__(self):
        print('Running D.__init__')
        super(D2,self).__init__()

bar = D2()
然后init调用链就变成了

Running D.__init__
Running B.__init__
Running A.__init__
因此,对
C.\uuuu init\uuuu
的调用被完全跳过


没有一个首选方案

如果您可以保证您不想支持多重继承,那么 显式父调用更简单、更清晰


如果希望现在或将来支持多重继承,则需要使用
super()
。但是要明白,使用super涉及到很多问题,但是这些缺陷是可以避免的。

super(Child,self)的主要目的是允许在使用菱形继承结构的多重继承的情况下正确运行初始化。如果使用多重继承显式调用基类构造函数,则某些初始值设定项可能会被调用两次。对于单继承,使用super和显式调用基类
\uuu init\uuu()
方法在功能上没有区别。请注意,因为所有python新型类都是对象的子类,所以多重继承总是涉及菱形继承

如果重命名或更改基类,super在减少所需更改方面的好处较小


在Python3中,
super
的参数是可选的,因此您只需执行
super()。Python 2仍然要求您显式地提供参数。

最后一个参数为您提供了
类型错误:必须使用父实例作为第一个参数来调用unbound方法\uuuu init\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuo()(没有得到任何内容)
,这正是因为缺少参数。
我相信你的意思是我喜欢这种方法,因为它对我来说更明确。。。MRO是可怕的黑色魔法,对不起,我想我的意思是让我改变它。谢谢各位,我编辑了标签和代码。制作一个。然后超级调用将调用与调用父类不同的
init
方法。\uuuu init\uuuu
。也许我遗漏了什么,但第二个示例实际上似乎没有调用显式类init。它只调用super,就像上面的例子一样。第二个例子首先调用super,但是B2调用的是一个.\uuu init\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。