Contacting Your Ancestors This Slice will focus on how to contact your ancestors in the inheritance tree. Since a séance is not really practical, we are left with two approaches: 1 Indirect calling using the super built-in type 2 Direct calling with unbound method calls This Slice will provide an overview of using both methods and take a quick look under the hood as well. Super Overview and Limitations The purpose of the super built-in is to smoothly delegate method calls for classes in the ancestor tree of an instance. That works best if the classes are designed cooperatively, which means: 1 All classes must be a subclass of object. 2 The method being called by super must exist. 3 The call signature for the caller and called method must be identical. 4 Each occurrence of the method uses super, except the root class. First, take a look at a simple single inheritance (SI) class hierarchy where each class has a method named method1 that simply announces it is running and then uses either an unbound method or super to call the next ancestor's version of the method. The usage of unbound method or super is determined by the u and s flags set at the top of the code. The entire text of this Example 1 file and Example 2 are at the end of this Slice. Example 1: A Simple Inheritance Tree # begin code u = 0 # 1 = use, 0 = do not use unbound methods s = 0 # 1 = use, 0 = do not use super assert not(s and u), 'both flags cannot be True' class Top(object): def method1(self): print 'processing Top' class Middle(Top): def method1(self): print 'processing Middle' if s: super(Middle, self).method1() if u: Top.method1(self) class Bottom(Middle): def method1(self): print 'processing Bottom' if s: super(Bottom, self).method1() if u: Middle.method(self) # create an instance of Bottom and run method1 b = Bottom() # make an instance b.method1() # run method1 # suspend code Running the above file unchanged will only run method1 in Bottom so it prints: processing Bottom Changing the s flag to 1 uses the super calls and prints: processing Bottom processing Middle processing Top What Super Does Many programmers think that calling super(Bottom, self) returns the immediate parent or super class of Bottom, which in this case is Middle. But that is not correct, according to the documentation: "super(type[, object-or-type]) Return a proxy object that delegates method calls to a parent or sibling class of type. This is useful for accessing inherited methods that have been overridden in a class. The search order is same as that used by getattr() except that the type itself is skipped." That is quite a mouthful, so lets take a closer look. Comparing Super with the Actual Parent First lets take a look at what super actually returns by activating and running the following code in Example 1. Note to activate code that is 'commented out' by triple quotes, prepend a hash (#) symbol to both triple quotes. # resume code # Note: change both """ to #""" to activate this """ # compare super(Bottom, b) and parent of Bottom print 'super of Bottom is:' print super(Bottom, b) print 'parent of bottom is Middle' print Middle """ # end code Which prints something like: <super: <class 'Bottom'>, <Bottom object>> <class '__main__.Middle'> Well clearly super(Bottom, b) does not return Middle. As noted in the documentation super returns a proxy object and that is what that ,<super <class ...>> thing is. What the Proxy Does The proxy determines the nearest ancestor of a class in an inheritance tree according to a linearization algorithm called the c3 algorithm. For single inheritance trees that turns out to be the obvious choice the parent. The proxy delegates the method call to that ancestor. A proxy object is needed because of Python's support of multiple inheritance (MI). If you have a class X that inherits from both A1 and A2 for example class X(A1, A2): What is the super class of X? Is it A1 or A2 (or both)? The proxy object determines the answer through that c3 algorithm, which uses the MRO (method Resolution Order)discussed in a previous Slice. MI trees will be discussed later in this Slice. Some Single Inheritance Examples In our example 1 code with s=1 and u=0, instance b calls method1 in Bottom, which prints its message. Bottom's method1 then uses super to call method1 in Middle, which prints its message. Middle's method1 then uses super to call method1 in Top, which prints its message. So the output is: processing Bottom processing Middle processing Top Change the s flag to 0 and the u flag to 1 and the output is the same, only the unbounded calls are not as indirect as super. Super lets you call a method without directly specifying a class name. This indirection can make adding a new class simpler since the called class is not specified. Now change the name of method1 in Middle and run it again twice, once with s=1 and once with u=1. You now get: processing Bottom processing Top In this case after running method1 in Bottom, the proxy tries to call method1 in Middle. Since Middle does not have a method1, the search continues up the tree to Top. Top has a method1, which is then called. That is probably what you want it to do. Since Top's version of method1 is not overridden by a method1 in Middle, the system uses the first match found above Middle in the inheritance tree. This is doing more than just trying to use the parent of Bottom. Instead the proxy returned by super searches for a valid method1 in the tree of classes starting with the parent of Bottom. Note that using an unbound method call to Middle has the same effect. Using either super or unbound method calls have the same effect: They both initiate an MRO search and the first occurrence of method1 found is called. Example 2 A Multiple Inheritance Tree Our second example is a tree with a closed diamond shape. There is a Top class that inherits object. Then a Left class and a Right class below and to the left and right both inheriting Top. And finally the Bottom class below and in the center inheriting from Left and Right. To start, we are using all unbound method calls. # begin code u = 1 # 1 = use, 0 = do not use unbound methods s = 0 # 1 = use, 0 = do not use super assert not(s and u), 'both flags cannot be True' class Top(object): def method1(self): print 'processing Top' class Left(Top): def method1(self): print 'processing Left' if s: super(Left, self).method1() if u: Top.method1(self) class Right(Top): def method1(self): print 'processing Right' if s: super(Right, self).method1() if u: Top.method1(self) class Bottom(Left, Right): def method1(self): print 'processing Bottom' if s: super(Bottom, self).method1() if u: Left.method1(self) if u: Right.method1(self) # create an instance and run method1 b = Bottom() # make an instance b.method1() # run method1 # end code The Problem with MI Trees When you run Example 2 you get: processing Bottom processing Left processing Top processing Right processing Top Now top runs twice! That could cause some problems. You may not think this diamond inheritance tree very likely in your code, but with the requirement that all classes either inherit object directly or inherit from a descendent of object, makes almost any MI tree a diamond. This is just the sort of problem that super was built to solve. Change the flags in Example 2 to u=0 and s=1 and run it again, you should get: processing Bottom processing Left processing Right processing Top The problem is solved for cooperative classes that are designed to work together using super. For now I recommend that you stick to single inheritance designs and avoid all the problems associated with multiple inheritance. Contacting Ancestors You can call any ancestor's method if it is visible by using an unbound method calls such as: inside a class ClassName.methodName(self, args) outside a class with an instance x ClassName.methodName(x, args) And you use super inside a class like this- super(ClassName, self).methodName(args) The code for Example 1 and 2 follow (2 spaces each level of indent. Example 1 # begin code u = 0 # 1 = use, 0 = do not use unbound methods s = 0 # 1 = use, 0 = do not use super assert not(s and u), 'both flags cannot be True' class Top(object): def method1(self): print 'processing Top' class Middle(Top): def method1(self): print 'processing Middle' if s: super(Middle, self).method1() if u: Top.method1(self) class Bottom(Middle): def method1(self): print 'processing Bottom' if s: super(Bottom, self).method1() if u: Middle.method(self) # ccreate an instance of Bottom and run method1 b = Bottom() # make an instance b.method1() # run method1 # suspend code # resume code # Note: change both """ to #""" to activate this """ # compare super(Bottom, b) and parent of Bottom print 'super of Bottom is:' print super(Bottom, b) print 'parent of bottom is Middle' print Middle """ # end code Example 2 # begin code u = 1 # 1 = use, 0 = do not use unbound methods s = 0 # 1 = use, 0 = do not use super assert not(s and u), 'both flags cannot be True' class Top(object): def method1(self): print 'processing Top' class Left(Top): def method1(self): print 'processing Left' if s: super(Left, self).method1() if u: Top.method1(self) class Right(Top): def method1(self): print 'processing Right' if s: super(Right, self).method1() if u: Top.method1(self) class Bottom(Left, Right): def method1(self): print 'processing Bottom' if s: super(Bottom, self).method1() if u: Left.method1(self) if u: Right.method1(self) # ccreate an instance and run method1 b = Bottom() # make an instance b.method1() # run method1 # end code