Python multi-inheritance, __init__
If you want to use super
in child
to call parent.__init__
and parent2._init__
, then both parent __init__
s must also call 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)
See "Python super method and calling alternatives" for more details on the sequence of calls to __init__
caused by using super
.
class Base(object): def __init__(self,*args): passclass parent(Base): var1=1 var2=2 def __init__(self,x=1,y=2): super(parent,self).__init__(x,y) self.var1=x self.var2=yclass 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.var5class child(parent, parent2): var3=5 def __init__(self,x,y): super(child, self).__init__(x,y)childobject = child(9,10)print childobject.var1print childobject.var2print childobject.var3childobject.parprint()
You might be wondering, "Why use Base
?". If parent
and parent2
had inherited directly from object
, then super(parent2,self).__init__(x,y)
would call object.__init__(x,y)
. That raises a TypeError
since object.__init__()
takes no parameters.
To workaround this issue, you can make a class Base
which accepts arguments to __init__
but does not pass them on to object.__init__
. With parent
and parent2
inheriting from Base
, you avoid the TypeError
.
Because parent
is next in method resolution order (MRO), and it never uses super()
to call into parent2
.
See this example:
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())
This will output:
Child called by ConstructParentA called by ChildParentB called by ParentABase called by ParentB[<class '__main__.Child'>, <class '__main__.ParentA'>, <class '__main__.ParentB'>, <class '__main__.Base'>, <class 'object'>]
Python multiple inheritance is like a chain, in Child
class mro
, the super
class of ParentA
is ParentB
, so you need call super().__init__()
in ParentA
to init ParentB
.
If you change super().__init__('ParentA')
to Base.__init__(self, 'ParentA')
, this will break the inheritance chain, output:
Child called by ConstructParentA called by ChildBase called by ParentA[<class '__main__.Child'>, <class '__main__.ParentA'>, <class '__main__.ParentB'>, <class '__main__.Base'>, <class 'object'>]