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.
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
def say_hello(cls):
print 'A says hello'
class B(A):
@classmethod
def say_hello(cls):
super(B, cls).say_hello()
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()
D.say_hello()
This example is for classmethods (not instance methods). | |
Note we pass | |
This prints out: A says hello
| |
This prints out (observe each method is called only once): A says hello
|
There is yet another way to use super:
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
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.