Programmer's Python - Multiple Inheritance
Written by Mike James   
Monday, 15 October 2018
Article Index
Programmer's Python - Multiple Inheritance
Multiple Inheritance - A Problem?
C3 And The mro

The Problem with Multiple Inheritance

If single inheritance is a good idea then surely multiple inheritance is an even better idea.

There is a problem, however, and it is quite a big problem – the so called diamond problem.

If you allow multiple inheritance then you have to face the fact that you might inherit the same class more than once.

For example, if B and C inherit from A and D inherits from B and C then it potentially gets two copies of class A:

tree4

In Python as all classes inherit from object, potentially multiple copies of object are inherited whenever multiple inheritance is used. That is, the diamond problem occurs even in the simplest of multiple inheritance.

To inherit from more than one class all you have to do is create the new class with a list of base classes.

For example:

class A:
    myAttribute = 42
class B(A):
    myAttribute = 43
class C(A):
    myAttribute = 44
class D(C,B):
    myAttribute = 45

This creates the diamond inheritance shown in the diagram, there is also the fact that all classes inherit from object which is ignored for the moment.

In general when you use:

class D(C,B)

then all of the classes in the list, C and B in this case, and their superclasses are included in the inheritance. The general situation can be complicated with lots of classes being involved – in practice things are usually much simpler.

Even if you ignore the duplicate class problem there is still the problem of which of C or B is the superclass of D? It might even be, as many assume, that both C and B are the superclass of D.

In fact this is the key to working with multiple inheritance.

Linearization

So how does Python solve the problem that D seems to have inherited two copies or perhaps two potential routes to class A, and what is the superclass of D, is it C, B or both C and B?

The answer to this question comes from considering the problem of what:

super(D,self) 

means, i.e. which class is the immediate superclass to D?

This turns out to be a matter of determining the mro, method resolution order, which is what super is based on. In single inheritance there is an inheritance chain of derived classes which is trivially taken as the mro. This makes it easy to determine what is the superclass of each class in the chain, and it fixes the order that the classes supply methods that are not defined earlier in the chain.

In multiple inheritance there isn’t a simple inheritance chain – there may be multiple such chains. For example, in the case we have been looking at there is a chain:

D → B → A 

and a chain:

D → C → A

If we view multiple inheritance not as a way to create inheritance graphs or multiple chains of inheritance, but as a way of creating a chain of inheritance that otherwise would be difficult to create.

It is clear that in the diamond example A is the least derived class and should be at the top of the chain i.e. last to be used to supply a method. The classes B and C are level on how derived they are, so lets assume that we can take them in any fixed order, and lastly D is at the start of the chain.

So we could say that:

class A: pass
class B(A): pass 
class C(A): pass
class D(C,B): pass

is a way of specifying the inheritance chain:

D → C → B → A

This is called linearizing the inheritance graph and it makes it possible to treat multiple inheritance as something very like single inheritance.

Once you have your linearized inheritance chain you have the mro and you have a definitive answer as to which class is the superclass of any other class, and each class has exactly one superclass.

Notice that we do have something new with multiple inheritance in that to create the inheritance chain:

D → C → B → A 

using single inheritance C would have had to inherit from B and this would mean than any use of C in any other inheritance chain would have had C inheriting from B. Put in another way, multiple inheritance has made it possible to “slip in” C into an inheritance chain where it otherwise would not have fitted. This is exactly what we want to be able to do if C is a mixin that has nothing to do with the rest of the class hierarchy.

Now that we have the idea of linearization it is time to find out how to do it.



Last Updated ( Monday, 15 October 2018 )