4.12 Multiple Inheritance
In Python, a class may inherit from more than one superclass. This is called multiple inheritance. It is not absolutely essential, but it does have a few uses.
For example, lists, being mutable, cannot be used as keys in dictionaries. But suppose we need to use lists as keys. Suppose we aren't interested in looking up lists by their contents, but by their identities; that is, when we look up the same list object, we want to find it, but when we look up a different list object with the same contents, we do not. Here's what we can do.
First, we create a class Hashable that provides the functions that a dictionary needs to use an object as a key.3 See Figure 410. The two methods are __hash__(), which a dictionary calls to decide where in the
Figure 410 Class Hashable in Hashable.py, pre-version 2.1.
hash table to start looking for the key, and __cmp__(), which it calls to compare two keys to see if they are equal. Both our methods will use the id() built-in function, which returns a different integer for each object. Any object inheriting these methods from Hashable will be placed in a hash table by its identity, rather than by its contents.
Now all we have to do is create a kind of list that inherits from Hashable. It would be nice to have a class that inherits from both Hashable and list, but Python's list data type is not a class. However, there is a trivial way around that. The Python library contains a module with a class UserList, which behaves exactly like a list. (It contains a list and passes all list operations on to it.) Since UserList is a class, we can inherit from it. So we create a class ListKey, Figure 411, that is both a list and a Hashable. All the methods are provided by its superclasses. It doesn't need any contents of its own.
Figure 411 Class ListKey in ListKey.py.
To understand what is happening with multiple inheritance, we need to understand the order in which Python searches the superclasses to find a method. It is no longer as simple as searching from a class to its one superclass along a chain until you find the method. Suppose a class has two superclasses and they both define the method. Which one gets used? Or does Python raise an exception if there are more than one?
To examine this, we are using a contrived example. Consider the collection of five classes given in Figure 412. A picture of the inheritance hierarchy is shown in Figure 413.
Figure 412 Diamond inheritance example.
Figure 413 Class hierarchy, diamond inheritance example.
Class E inherits from both C and D; C and D both inherit from B; and B inherits from A. Notice that both B and D define a method f(). Suppose we have an instance of an E and call method f(). Which one do we get? Let's try it:
>>> import abcde >>> x=abcde.E() >>> x.f() f() in B
Okay, we get the f() method in B, even though the one in D is closer to E. In fact, the one in D lies between E and B. You might think that the definition of f() in D ought to hide the one in B from E.
The way it actually works, Python does a depth-first search for the method. When it comes to a class with more than one superclass, Python searches them and their superclasses one at a time, from left to right. So the search path from E would be E, C, B, A; then, after backing down to E, up again to D, B, and A. So, looking for f(), Python will examine E and C and then find it in B. Python won't look any further to see it in D. This leads some people to argue that the search order should be "depth first up to joins." Since the paths join at B, B wouldn't be searched until both C and D have been, but that's not how Python does it.
The contour diagram we used in Figure 44 won't work as easily here, since the box for one class is not enclosed in a single box. But we can use the contour model if we are willing to have classes included more than once. The boxes for the search path C-B-A would be included in the boxes for the search path D-B-A, as shown in Figure 414.
Figure 414 Contours for abcde.