Home > Articles > Open Source > Python

  • Print
  • + Share This
This chapter is from the book

This chapter is from the book

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 4–10. The two methods are __hash__(), which a dictionary calls to decide where in the

Figure 4-10Figure 4–10 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 4–11, 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 4-11Figure 4–11 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 4–12. A picture of the inheritance hierarchy is shown in Figure 4–13.

Figure 4-12Figure 4–12 Diamond inheritance example.

Figure 4-13Figure 4–13 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 4–4 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 4–14.

Figure 4-14Figure 4–14 Contours for abcde.

  • + Share This
  • 🔖 Save To Your Account