Multiple Inheritance in Python

Ulf Hamster 2 min.
python multiple inheritance diamond problem

Parent Classes

If a set of parent classes contain distinct attributes and methods, and have the purpose to be used in child classes (abstract classes) they are called “mixin”

Here we look at at child classes that have same method names (e.g., get())

class ThingAlpha(object):
    def __init__(self, a):
        self.a = a
        print("Alpha")
    def get(self):
        return self.a

class ThingBeta(object):
    def __init__(self, b):
        self.b = b
        print("Beta")
    def get(self):
        return self.b

Simple Inheritance: Child-Parent

ThingChild has only 1 parent class ThingAlpha. super(ThingsChild, self).__init__(args, ..) will forward the arguments to just one parent class. In case of simple inheritance there is no issue with that as there is just one parent class.

class MyChild(ThingAlpha):
    def __init__(self, a, c):
        super(MyChild, self).__init__(a)  # instantiate the parent=super class
        self.c = c  # our child class adds this
    def get(self):
        return [super(MyChild, self).get(), self.c]

obj = MyChild(1,3)
obj.get()
Alpha





[1, 3]

Multiple Inheritance: Call a specific parent class

If you want to make sure that all parent classes are intantiate, then call each parent explicitly (don't use super. super is not so super for this)

class ThingsCombined(ThingAlpha, ThingBeta):
    def __init__(self, a, b, c):
        ThingAlpha.__init__(self, a)
        ThingBeta.__init__(self, b)
        self.c = c  # our additional sauce
    def get(self):
        return [ThingAlpha.get(self), ThingBeta.get(self), self.c]

obj = ThingsCombined(1,2,3)
obj.get()
Alpha
Beta





[1, 2, 3]

Multiple Inheritance: Diamonds

The diamond problem is use case of multiple inheritance where super works. We have three levels of classes

  1. The ultimative parent MasterParent
  2. Two or more variants ThingA(MasterParent), ThingB(MasterParent), etc.
  3. And your child class OurChild uses super to call all parent classes
class MasterParent:
    def __init__(self, wisdom):
        self.wisdom = wisdom.split()
        print("the master parent holds the wisdom of everything")
    def get(self):
        return self.wisdom

class ThingA(MasterParent):
    def __init__(self, wisdom):
        super().__init__(wisdom)
        self.a = self.wisdom[0] if len(self.wisdom) > 0 else None
    def get(self):
        return self.a

class ThingB(MasterParent):
    def __init__(self, wisdom, b=None):
        super().__init__(wisdom)
        self.b = self.wisdom[1] if len(self.wisdom) > 1 else None
    def get(self):
        return self.b

class ThingC(MasterParent):
    def __init__(self, wisdom, c=None):
        super().__init__(wisdom)
        self.c = self.wisdom[2] if len(self.wisdom) > 3 else None
    def get(self):
        return self.c


class OurChild(ThingA, ThingB, ThingC):
    def __init__(self, wisdom):
        super(OurChild, self).__init__(wisdom)
    def get(self):
        return [ThingA.get(self), ThingB.get(self), ThingC.get(self)]
    
obj = OurChild("Computers are useless. They can only give you answers")
print(obj.get())

obj = OurChild("Computers are")
print(obj.get())

the master parent holds the wisdom of everything
['Computers', 'are', 'useless.']
the master parent holds the wisdom of everything
['Computers', 'are', None]