A Super Solution

Python provides a class attribute __mro__ for each class, and a type called super. The __mro__ attribute is a tuple containing the class itself and all of its superclasses without duplicates in a predictable order. A super object is used in place of the find_out_whos_next() method.

Example 2.5. One super technique

class B(A): 1
    def do_your_stuff(self):
        super(B, self).do_your_stuff() 2
        # do stuff with self for B



2

The super() call creates a super object. It finds the next class after B in self.__class__.__mro__. Attributes accessed on the super object are searched on the next class and returned. Descriptors are resolved. What this means is accessing a method (as above) returns a bound method (note the do_your_stuff() call does not pass self). When using super() the first parameter should always be the same as the class in which it is being used (1).

If we're using a class method, we don't have an instance self to pass into the super call. Fortunately for us, super works even with a class as the second argument. Observe that above, super uses self only to get at self.__class__.__mro__. The class can be passed directly to super as shown below.

Example 2.6. Using super with a class method

class A(object):
    @classmethod 1
    def say_hello(cls):
        print 'A says hello'

class B(A):
    @classmethod
    def say_hello(cls):
        super(B, cls).say_hello() 2
        print 'B says hello'

class C(A):
    @classmethod
    def say_hello(cls):
        super(C, cls).say_hello()
        print 'C says hello'

class D(B, C):
    @classmethod
    def say_hello(cls):
        super(D, cls).say_hello()
        print 'D says hello'

B.say_hello() 3
D.say_hello() 4


1

This example is for classmethods (not instance methods).

2

Note we pass cls (the class and not the instance) to super().

3

This prints out:

A says hello
B says hello

4

This prints out (observe each method is called only once):

A says hello
C says hello
B says hello
D says hello

There is yet another way to use super:

Example 2.7. Another super technique

class B(A):

    def do_your_stuff(self):
        self.__super.do_your_stuff()
        # do stuff with self for B

B._B__super = super(B) 1


When created with only a type, the super instance behaves like a descriptor. This means (if d is an instance of D) that super(B).__get__(d) returns the same thing as super(B,d). In 1 above, we munge an attribute name, similar to what Python does for names starting with double underscore inside the class. So this is accessible as self.__super within the body of the class. If we didn't use a class specific attribute name, accessing the attribute through the instance self might return an object defined in a subclass.

While using super we typically use only one super call in one method even if the class has multiple bases. Also, it is a good programming practice to use super instead of calling methods directly on a base class.

A possible pitfall appears if do_your_stuff() accepts different arguments for C and A. This is because, if we use super in B to call do_your_stuff() on the next class, we don't know if it is going to be called on A or C. If this scenario is unavoidable, a case specific solution might be required.