Search code examples
pythonmultiple-inheritancemixinssuper

Python mixin constructor not called when final class has no __init__


Final class user might want to create a a class composed from Base and Mixin (Mixin provides additional common functionality over a 3rd party library classes).

But the Mixin.__init__ is not called when used as below. Only Base.__init__ is called:

>>> class Base(object): #3rd party library class
...     def __init__(self): print "Base"
... 
>>> class Mixin(object): #my features useful as addendum for a few classes
...     def __init__(self): print "Mixin"
... 
>>> class C(Base, Mixin): pass
... 
>>> c = C()
Base

How to enforce calling both Mixin.__init__ and Base.__init__ in this scenario without requiring the user to remember to put a constructor with super() call in C class?

>>> class Base(object):
...     def __init__(self): print "Base"
... 
>>> class Mixin(object):
...     def __init__(self): print "Mixin"
... 
>>> class C(Base, Mixin): 
...    #easy to forget to add constructor 
...    def __init__(self): super(C, self).__init__()
... 
>>> c = C()
Base
Mixin

Solution

  • Python doesn't chain any method calls like this automatically, so you need to be disciplined and use cooperative inheritance correctly. If one class uses super, then all classes must use super. (This is a simple case, since none of the overriden __init__ methods add any additional arguments. If they did, you would need to do some work to ensure that object.__init__ never received additional arguments once it was called.)

    Read https://rhettinger.wordpress.com/2011/05/26/super-considered-super/ before continuing.

    class Base(object):
        def __init__(self):
            print "Base"
            super(Base, self).__init__()
    
    class Mixin(object):
        def __init__(self):
            print "Mixin"
            super(Mixin, self).__init__()
    
    class C(Base, Mixin): 
        pass
    
    c = C()
    

    (This is also a perfect example of why you need to understand how super works, and not treat it as simple indirect reference to your class's base class.)

    If you can't modify Base or Mixin to use super, then you'll need to define wrappers around them that can. The linked article explains how.