Python 多重继承,__init__

29 投票
3 回答
23777 浏览
提问于 2025-04-17 09:19

关于多重继承,当我调用 super.__init__ 时,为什么 parent2 的 __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

3 个回答

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(方法解析顺序)中,ParentA的父类是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 的更多信息

10

因为parent在方法解析顺序(MRO)中排在后面,而且它从来没有使用super()去调用parent2

27

如果你想在child类中使用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)

想了解更多关于使用super__init__调用顺序的细节,可以查看这个链接:"Python super method and calling alternatives"


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错误。

撰写回答