Calling a Superclass Implementation of a Method

Credit: Alex Martelli

Problem

You need functionality equivalent to Java’s super keyword to delegate part of a method to a superclass.

Solution

When you override the method of a superclass, you often want to call the superclass’s version of a method as part of your override. In a Python 2.2 new-style class, the new built-in super function helps a lot:

class A(B, C):
    def amethod(self):
        # First, call the superclass's version
        super(A, self).amethod(  )
        # Continue with A-specific implementation
        ...

With super, you transparently call amethod in the B or C superclass, or in both, if both classes define it, and B also uses super in the same way.

This doesn’t work for classic classes (or in Python 2.1 and earlier), but we can arrange for a slightly weaker version:

def super(class_, inst):
    # First, try the real thing, if available and applicable
    try: return _ _builtins_ _.super(class_, inst)
    except (TypeError, AttributeError): pass
    # Otherwise, arrange for a weaker substitute
    class Super:
        def _ _init_ _(self, class_, inst):
            # Just remember the bases and instance
            self.bases = class_._ _bases_ _
            self.inst = inst
        def _ _getattr_ _(self, name):
            # Seek the bases for an unbound method; break when found
            for base in self.bases:
                method = getattr(name, method, None)
                if method is not None: break
            else: raise AttributeError, name  # No base has it, so raise
            # Found, so create and return the bound-method version
            import new
            return new.instancemethod(method, self.inst, method.im_class)

Used in a classic class, this super calls a method only in the base where it first finds it. In classic-class settings, to call a method in all superclasses that have it, use the approaches shown in Recipe 5.4.

Discussion

When you override a method, it is quite common to want to delegate part of its execution to a superclass. In other words, even though you are overriding the method to provide extra features, you still need to use the superclass’s implementation as part of your own. If there is just a single superclass, or if you know which superclass implementation you need to call, it is easy to do this with the normal Python idiom Superclass.themethod(self, ...). However, with multiple inheritance, you may not know which superclass you want. If you refactor your code, you may move methods between superclasses, so you shouldn’t depend on a method’s exact location in the subclass you’re writing. Often, you may want to call all implementations of a method in all superclasses, particularly for special methods, such as _ _init_ _ or _ _del_ _.

Python 2.2’s new-style object model offers a direct solution for this task: the new super built-in function. You call super with two arguments: the class in which you’re overriding the method and self. Looking up any method on super’s return value returns the appropriate superclass implementation to call as a bound method (i.e., you don’t explicitly pass it self again). If you use this technique systematically in all the classes that override this method, you end up calling every superclass implementation (in the new-style model’s canonical method resolution order, so you don’t have to worry about diamond-shaped inheritance graphs).

In the classic object model, super doesn’t work (and in Python 2.1 and earlier, it doesn’t even exist). In this recipe, we simulate it in a slightly weaker but still useful way. The recipe defines a factory function (i.e., a function that builds and returns a suitable object) also called super, so that it shadows the built-in super from normal use. You use it as you use the built-in super, except that you can use it in classic or new-style classes interchangeably. The recipe’s function first tries to use the built-in super. If that’s not found or not applicable, the function falls back to the slightly weaker but useful equivalent, the Super class.

The Super class does not let you transparently call a method in several superclasses, nor does it apply the new-style method resolution order. However, it does work for simple cases. _ _init_ _ simply stashes away the instance and the list of bases. _ _getattr_ _ loops on all bases; if the loop does not find the method, and thus never breaks, the else clause is entered, which raises AttributeError. If the method is found, _ _getattr_ _ wraps it into a bound method (the better to simulate the built-in super’s workings) and returns it. The wrapping is performed via the instancemethod function in the new module using the im_class attribute of the unbound method, which records the class that supplied the method.

Get Python Cookbook now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.