Python多重继承,__init__

29

关于多重继承,当我调用super.__init__时,为什么父类2的__init__函数没有被调用?谢谢。

class parent(object):
    var1=1
    var2=2
    def __init__(self,x=1,y=2):
        self.var1=x
        self.var2=y

class parent2(object):
    var4=11
    var5=12
    def __init__(self,x=3,y=4):
        self.var4=x
        self.var5=y

    def parprint(self):
        print self.var4
        print self.var5

class child(parent, parent2):
    var3=5
    def __init__(self,x,y):
        super(child, self).__init__(x,y)

childobject = child(9,10)
print childobject.var1
print childobject.var2
print childobject.var3
childobject.parprint()

输出结果为

9
10
5
11
12

2
附注:http://rhettinger.wordpress.com/2011/05/26/super-considered-super/ 很好地解释了 super,并展示了它如何与多重继承相协调。 - user395760
4
请将类名首字母大写。 - e9t
3个回答

27
如果你想在子类中使用super来调用父类的parent.__init__parent2._init__,那么父类的两个__init__方法也必须都调用super
class parent(Base):
    def __init__(self,x=1,y=2):
        super(parent,self).__init__(x,y)   

class parent2(Base):
    def __init__(self,x=3,y=4):
        super(parent2,self).__init__(x,y)

请查看"Python super方法及调用替代方法",了解使用super导致的__init__调用顺序的更多详细信息。

class Base(object): 
    def __init__(self,*args):
        pass

class parent(Base):
    var1=1
    var2=2
    def __init__(self,x=1,y=2):
        super(parent,self).__init__(x,y)        
        self.var1=x
        self.var2=y

class parent2(Base):
    var4=11
    var5=12
    def __init__(self,x=3,y=4):
        super(parent2,self).__init__(x,y)
        self.var4=x
        self.var5=y

    def parprint(self):
        print self.var4
        print self.var5

class child(parent, parent2):
    var3=5
    def __init__(self,x,y):
        super(child, self).__init__(x,y)


childobject = child(9,10)
print childobject.var1
print childobject.var2
print childobject.var3
childobject.parprint()
你可能会想:“为什么要使用 Base?” 如果 parentparent2 直接从 object 继承,那么 super(parent2,self).__init__(x,y) 将调用 object.__init__(x,y)。这将引发 TypeError,因为 object.__init__() 不接受参数。
为了解决这个问题,你可以创建一个类 Base,它接受 __init__ 的参数但不将它们传递给 object.__init__。使用 parentparent2 继承自 Base,你就避免了 TypeError

10

谢谢,但对于父类来说,它的超类是对象?如果要调用parent2,应该怎么做? - Renl
1
当涉及到MI时,MRO不关心当前超类是什么。 - Ignacio Vazquez-Abrams

6

看这个例子:

class Base(object): 
    def __init__(self, c):
        print('Base called by {0}'.format(c))
        super().__init__()

class ParentA(Base):
    def __init__(self, c):
        print('ParentA called by {0}'.format(c))
        super().__init__('ParentA')

class ParentB(Base):
    def __init__(self, c):
        print('ParentB called by {0}'.format(c))
        super().__init__('ParentB')

class Child(ParentA, ParentB):
    def __init__(self, c):
        print('Child called by {0}'.format(c))
        super().__init__('Child')

Child('Construct')
print(Child.mro())

这将输出:
Child called by Construct
ParentA called by Child
ParentB called by ParentA
Base called by ParentB
[<class '__main__.Child'>, <class '__main__.ParentA'>, <class '__main__.ParentB'>, <class '__main__.Base'>, <class 'object'>]

Python多重继承就像一条链,在Child类的mro中,ParentAsuper类是ParentB,因此你需要在ParentA中调用super().__init__()来初始化ParentB

如果你将super().__init__('ParentA')改为Base.__init__(self, 'ParentA'),这将会打破继承链,输出:

Child called by Construct
ParentA called by Child
Base called by ParentA
[<class '__main__.Child'>, <class '__main__.ParentA'>, <class '__main__.ParentB'>, <class '__main__.Base'>, <class 'object'>]

有关MRO的更多信息


1
你应该指出你的示例是针对Python 3的。在Python 2中,没有参数的super()将会失败。 - djangonaut

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接