Calling __init__ with multiple inheritance

Peter Otten __peter__ at web.de
Mon Mar 28 14:53:04 EST 2005


jfj wrote:

> As for the case where the users of the library want to subclass, I don't
> see a problem.  They know they must subclass from class XXX and so they
> call XXX.__init__ to construct it.

I was thinking of 

class Child(Father, Mother):
    pass

where Father and Mother have a common base class Parent. That would be
initialized twice:

>>> class Parent(object):
...     def __init__(self):
...             print "parent"
...
>>> class Father(Parent):
...     def __init__(self):
...             print "father"
...             Parent.__init__(self)
...
>>> class Mother(Parent):
...     def __init__(self):
...             print "mother"
...             Parent.__init__(self)
...
>>> class Child(Father, Mother):
...     def __init__(self):
...             print "child"
...             Father.__init__(self)
...             Mother.__init__(self)
...
>>> Father()
father
parent
<__main__.Father object at 0x402ad66c>
>>> Mother()
mother
parent
<__main__.Mother object at 0x402ad38c>
>>> Child()
child
father
parent
mother
parent # <-- the culprit: parent initialized a second time
<__main__.Child object at 0x402ad66c>

You have several options now:
- Write __init__() in such a way that calling it twice does no harm
- Ensure that it is only called once by adding a self.initialized flag
- Document that a user class may not inherit from both Father and Mother
but the best is IMO
- let super() do the work

> In the case of Parent diamond inheritance, super() can avoid calling
> the __init__ of parent twice?  How?

That's the best part -- it's automatic:

>>> class Parent(object):
...     def __init__(self):
...             print "parent"
...             super(Parent, self).__init__()
...
>>> class Father(Parent):
...     def __init__(self):
...             print "father"
...             super(Father, self).__init__()
...
>>> class Mother(Parent):
...     def __init__(self):
...             print "mother"
...             super(Mother, self).__init__()
...
>>> class Child(Father, Mother):
...     def __init__(self):
...             print "child"
...             super(Child, self).__init__()
...
>>> Father()
father
parent
<__main__.Father object at 0x402ad38c>
>>> Mother()
mother
parent
<__main__.Mother object at 0x402ad3cc>
>>> Child()
child
father
mother
parent # <-- parent only once
<__main__.Child object at 0x402ad38c>

That was a lot of dull code -- but you asked :-)
Seriously, I think super() scales better in a scenario with multiple
inheritance, though I won't start a holy war about the issue.

Peter
 




More information about the Python-list mailing list