Overriding Class Methods in Python
One of the features added back in Python 2.2 was class methods. These differ from traditional methods in the following ways:
- They can be called on both the class itself and instances of the class.
- Rather than binding to an instance, they bind to the class. This means that the first argument passed to the method is a class object rather than an instance.
For most intents and purposes, class methods are written the same way as normal instance methods. One place that things differ is overriding a class method in a subclass. The following simple example demonstrates the problem:
class SubClass(ParentClass): @classmethod def create(cls, arg): ret = ParentClass.create(cls, arg) ret.dosomethingelse() return ret
This code is broken because the
ParentClass.create() call is calling
the version of
create() method in the context of
rather than calling an unbound method like it would with a normal
instance method. The most likely outcome will be a
TypeError due to
the method receiving too many arguments.
So how do you chain up to the parent class implementation? You use the
super() object, which was also added in Python 2.2 as an alternative
way to chain to the parent implementation of a method. The above code
rewritten as follows:
class SubClass(ParentClass): @classmethod def create(cls, arg): ret = super(SubClass, cls).create(arg) ret.dosomethingelse() return ret
If you haven't ever used the
super() object, this is what it is
doing in the above example:
SubClassis looked up in the list
cls.__mro__(a linearised list of ancestor classes in the order used for method resolution).
- The class dict for each ancestor class coming after
cls.__mro__is checked to see if it contains "
super()object returns a version of "
create" in the context of
__get__(cls)"descriptor get" method.
- When this bound method gets called,
clswill be passed in instead of the parent class.
Previously I'd ignored
super() for the most part, since I could
use the old chaining syntax. This shows a place where the old-style
syntax can't be applied.
Looks a lot like Ruby.
James Henstridge -
From my quick reading of some Ruby documentation, it says that "super" is a keyword.
In Python, it is just another object. In fact, it could easily be rewritten in Python as seen here: http://www.python.org/2.2/descrintro.html#superexample
It is just an application of the descriptor features added back then.
Geoff Gerrietts -
SubClass and Subclass are mixed throughout the code examples. That's not intentional is it?
James Henstridge -
Thanks for pointing that out. I was adapting a real example, and made some mistakes when transcribing it.