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

Python supports multiple inheritance which can be scary, but the trick is to make it as much like single inheritance as possible and this is what Python does. This extract is from my new book with the subtitle "Something Completely Different".

Programmer's Python
Everything is an Object

Is now available as a print book: Amazon

pythoncover


Contents

  1. Hello Python World
  2. Variables, Objects and Attributes
  3. The Function Object
    Extract - Function Objects
  4. Scope, Lifetime and Closure
    Extract - Local and Global  ***NEW
  5. Advanced Functions
    Extract -  Decorators 
  6. Class Methods and Constructors
  7. Inside Class
  8. Metaclass
  9. Advanced Attributes
    Extract - Properties
  10. Custom Attribute Access
  11. Single Inheritance
  12. Multiple Inheritance
  13. Class and Type
  14. Type Annotation
  15. More Magic - Operator Overloading

 

Advanced Attributes

Multiple Inheritance

What has been described so far is inheritance as it happens in most other languages – single inheritance. In single inheritance every class has a single direct superclass.

Put another way, each class inherits from exactly one other class and if it doesn’t inherit explicitly then it inherits from object.

Single inheritance works well for code reuse and you can use it in more philosophical ways to model the real world of hierarchies. However, single inheritance often proves itself to be inadequate and languages have to invent alternative methods of allowing classes to conform to the specification of what attributes they have to have – the interface or the trait are good examples. However, what is interesting and it seems almost inevitable is that these constructs slowly evolve to reintroduce elements of multiple inheritance. For example, the interface in Java has evolved from not having method implementations to allow default method implementations which are for all intents and purposes “inherited”.

What this means is that even if you have heard bad things about multiple inheritance it is worth finding out more, and Python’s multiple inheritance is much more usable than most.

Why Multiple Inheritance?

Single inheritance creates a class hierarchy as one object inherits from another single object. While it is obvious that each object can only have one base class, an object can be a base class to many subclasses and this creates a tree or hierarchical relationship:

tree 

You can see in the diagram that if you focus on a single object, D say, then from D’s point of view the inheritance is a chain:

object→ A → D

This is simple and you can say that D has at least all of the attributes of A, which has at least all the attributes of object. In terms of code reuse you can interpret this chain as a reuse of code from object, to A, to D.

Now suppose that you have class G which has some methods that D could make use of. How can you give D these methods?

In other languages you would create G as an interface which is a collection of method definitions without implementation. D would then implement interface G by providing definitions for all of the methods. This ensures that D has all of the methods defined by G and this is useful but it isn’t code reuse. As already mentioned interfaces tend to evolve into something that does provide code reuse.

Suppose you wanted to add G to D’s inheritance chain.

Using single inheritance you would have to find a way to insert it into the existing chain. The only way to do this is to change A so that it inherited from G i.e.:

object→ G → A→ D 

or to change G so it inherited from A i.e.:

object→ A → G → D

If all we want to do is give D the methods that are defined in G then either of these options is more than we intend.

For example adding D to be A’s base class produces a hierarchy:

tree2

You can see that not only has D inherited G’s methods but also A, C and F have. If this is our intent then fine but if not then we need to look out for side effects.

The alternative, to make G inherit from A, has less of a “knock on” effect but notice that now you have permanently modified G so that inherits from A and any other class that want to use the methods in G also has to inherit methods from A. This is might be what you want but not usually.

If you want D to have the methods of G and you don’t want to affect the existing hierarchy then you have little choice but to resort to multiple inheritance. In this case G inherits from object and D from G. Class D no longer has an inheritance chain as it has two superclasses A and G, but the rest of the inheritance hierarchy is not changed. Also notice that the inheritance diagram is no longer a tree it is a graph.

So how common is this requirement?

It often happens that you need an object to have two or more different sets of attributes that reflect the different aspects of its role.

For example, a button class might need graphics methods so that it can draw itself, and event handling methods so that it can respond to user interaction. Graphical methods might well be bundled up into one class and event handling in another – the solution is to allow button to inherit from both.

If you think of a class as being a library of methods and in more general terms behaviors then multiple inheritance is a natural idea. You would happily load more than one library into your program so you could use its methods, why not take the same attitude with respect to classes?

A class that is used to simply supply some functionality, i.e. some methods to another is often called a mixin – although the term usually implies that some other mechanism than inheritance will be used to utilize it. Python has mixins of a sort but they are implemented using multiple inheritance.

Classes that are mixins usually have a very short inheritance chain but this is not always the case.



Last Updated ( Monday, 15 October 2018 )