r5 - 06 Feb 2006 - 07:32:41 - JimJJewettYou are here: OSAF >  Projects Web  >  ChandlerHome > DeveloperDocumentation > ChandlerCodingStyleGuidelines > UsingSuper

The Long and Short of Using =super

Using super() in your python code makes your code more readable and easier to maintain. It also plays a critical role when multiple inheritance is involved to ensure that the multiple superclasses each get called. The way this works can be surprising and a bit complicated, so it's covered in detail in the Long Notes on Super section below.

Short notes on Super

Overview

When subclassing, you often want to extend the behavior of a method instead of replacing it completely. Before super you would simply do this by calling the mehod on your superclass directly from your method. super allows you to make that method call in a more general way. When you use super, you supply your own class name, and it figures out the appropriate superclass to be called.

To use super, you usually do something like this:

   def aMethod(self, params):
      super(classname, self).aMethod(params)
      additions

where classname is the name of your class, params are the parameters to your method (minus self), and additions is the extra behavoir you are adding to the method.

Usage Guidelines

In Chandler, our goal is to use super everywhere. An exception is where we're subclassing another code module that does not use super.

  • You should always call super if you are extending the functionality of a method. This means any
    __init__
    or
    __del__
    method should always call super.

  • It's good practice to handle any additional arguments and pass them on, using *args to pick up extra positional arguments, and **kwds to pick up additional keyword arguments. See below for usage examples.

  • It is good practice not to need a return value (because of possible conflicts), but safest to return whatever super did (hopefully None), just in case.

  • Usage of super is important to making your code usable by others. Even though you may not be using multiple inheritance, and you know what your base classes are, you may still need to call super to make your code usable by subclasses. For example, you write a class that inherits directly from object. No need to call super, right? Wrong. Someone later subclasses off of your class, and they mixin an additional class. Now your code is being used in a multiple inheritance situation. If you failed to call super in your
    __init__
    method, the
    __init__
    method of their mixin class may never get called.

Trouble Shooting

  • If you get an error that says something like: super() argument 1 must be type, not classobj the problem is that you are using old-style python classes, which do not support super. The easy way to fix this is to put object at the base of your inheritance tree.
  • Use your own classname as the first parameter to super, not the class you expect to call
  • Pass all the arguments that came in to your method to your super's method call _except self_
  • If none of your superclasses defines the method you are calling super on, you will get an AttributeError. It's suggested that your wrap your call in a try block.

Long Notes on Super

When to call super

You have to make a judgement call when deciding if you should call super or not. Are you overriding the method, or just overloading (extending the functionality)? Will the clients of your class want to extend the functionality that you are providing?

Where to place your super call

A lot of the time you want to call super right at the beginning of your method. This is because the base class behavior is usually something that you build on top of, so you start with that. But there are many situations where you need to set the scene for the base class, so you put some functionality before the call to super. Also, be aware that a lot could happen during the super call, so any safe setup that you can do before calling super can help prevent problems in complicated situations, e.g. when you invite recusion by defining
__getattr__
. In summary, there are no hard and fast rules, except to think about the potential implications of the code you are writing.

What happens with MI?

When multiple inheritance is involved, things get more complicated. Now the inheritance tree is not a simple hierarchy, and there is more than one root of the tree. It's important to be able to give control to each of the roots of the tree, so they can initialize their portion of the object, etc. The way super does this is by linearizing the set of all superclasses into a single chain, and each call to super goes one step farther along the chain. This may end up linking to root of one tree a leaf from the next tree. The code sample below illustrates the linkage between trees done by super.

Code example

class M(object):
  """ Mixin class """
  def __init__(self, *args, **kwds):
    print 'init.M'
    super(M, self).__init__(*args, **kwds)

class B(object):
  """ Base class """
  def __init__(self, *args, **kwds):
    print 'init.B'
    super(B, self).__init__(*args, **kwds)

class D(B):
  """ Derived class """
  def __init__(self, *args, **kwds):
    print 'init.D'
    super(D, self).__init__(*args, **kwds)

class CL(M, D):
  """ Class Left """
  def __init__(self, *args, **kwds):
    print 'init.CL'
    super(CL, self).__init__(*args, **kwds)

class CR(D, M):
  """ Class Right """
  def __init__(self, *args, **kwds):
    print 'init.CR'
    super(CR, self).__init__(*args, **kwds)

When you execute cl = CL() you get the following output:

init.CL
init.M
init.D
init.B

When you execute cr = CR() you get:

init.CR
init.D
init.B
init.M

Note that in the first case M's call to super is critical to allowing the rest of the init calls to happen, even though its superclass is object. Equally important in the second case is B's call to super, even though its superclass is object.

Issues

Using super can be confusing. Hopefully this discussion, and other resources, help overcome this issue. Many of the newer books on Python do a good job addressing super, e.g. Python in a Nutshell, pages 88-89.

Intermixing usage of super and direct-call-to-superclass is dangerous. (Direct-to-currently-expected-superclass calls may skip or even repeat some super classes because of the different MRO used by super.) Here's a link from the Twisted folks that addresses this point, and gives their perspective on super: http://www.ai.mit.edu/people/jknight/super-harmful/

Sometimes calling super causes an error, because that method is not defined in any of your superclasses. As the example above illustrates, this can change when multiple inheritance is involved. If you think your class may be used in a multiple inheritance situation in the future, it makes sense to wrap the super method call with a try block.

  def f(self):
    """ f method of my general base class """
    print 'B'
    try:
      super(B, self).f()
    except AttributeError:
      pass # no f() in any super

-- DonnDenman - 26 Jul 2004

If you want to be extra careful, and not mask Exceptions raised by superclass methods, you need to create a temporary variable.

You may also want to return the result, for some methods.

  def f(self):
    """ f method of my general base class """
    print 'B'
    try:
      # Get the next method, but don't call it yet
      f=super(B, self).f
    except AttributeError:
      pass # no f() in any super
    # Now actually call the next method *outside*
    # of the except clause, in case *it* raises an
    # AttributeError.  If it has a return value,
    # we might as well pass it on.
    return f()
Edit | WYSIWYG | Attach | Printable | Raw View | Backlinks: Web, All Webs | History: r5 < r4 < r3 < r2 < r1 | More topic actions
 
Open Source Applications Foundation
Except where otherwise noted, this site and its content are licensed by OSAF under an Creative Commons License, Attribution Only 3.0.
See list of page contributors for attributions.