Search code examples
pythonclassmultiple-inheritance

python dynamic multiple inheritance __init__


I am trying to write a plugin environment where I need to do multiple inheritances on an unknown number of classes. Therefore, I have opted to use the type class creation:

class A(object):
   def __init__(self,s):
      self.a="a"
   def testA(self,x):
      print(x)

class B(object):
   def __init__(self,s):
      self.b="b"
   def testA(self,x):
      print(x)

C = type('C', (A,B), {})

x= C("test")
print x.b

When I run the above code, I get the error:

AttributeError: 'C' object has no attribute 'b'

This is because only the init for class A is being run when the instance for class C is initialized. My question is how can I get the class C to have both the init for class A as well as the init for class B to run when an instance of class C is initialized. I do realize that if I had class C like the following it would work:

class C(A,B):
    def __init__(self,s):
       A.__init__(self,s)
       B.__init__(self,s)

However, given that I need to have a dynamic list of classes inherited this will not work.


Solution

  • It seems you're using python 2 so I'm using this old python 2 super() syntax where you have to specify the class and the instance, although it would work in python 3 as well. In python 3 you could also use the shorter super() form without parameters.

    For multiple inheritance to work is important that the grandparent class __init__ signature matches the signature of all siblings for that method. To do that, define a common parent class (MyParent in this example) whose __init__ has the same parameter list as all the childs. It will take care of calling the object's __init__ that doesn't take any parameter, for us.

    from __future__ import print_function
    
    class MyParent(object):
        def __init__(self, s):
            super(MyParent, self).__init__()
    
    class A(MyParent):
        def __init__(self, s):
            self.a = "a"
            super(A, self).__init__(s)
        def testA(self, x):
            print(x)
    
    class B(MyParent):
        def __init__(self, s):
            self.b = "b"
            super(B, self).__init__(s)
    
        def testA(self,x):
            print(x)
    
    C = type('C', (A, B), {})
    
    x = C("test")
    print(x.b)
    

    You can define as many children to MyParent as you want, and then all __init__ methods will be called, provided you used super() correctly.