The @classmethod decorator

Sunday, March 15th 2015, 6:27 pm

I recently started spending a lot of time modifying an existing Python codebase. If you are not familiar with Python, Python is a scripting language with many nice touches that make your life as a programmer easier. I found one of such niceties while trying to modify an existing Python module: the @classmethod decorator. (If you are familiar with Python decorators, jump here to skip the introduction).

The @classmethod decorator, is a builtin function decorator that, according to the Python docs, has existed since Python 2.2. A function decorator is basically an expression that gets evaluated after your function is defined. The result of that evaluation shadows your function definition.

If you are a programmer with a Java or Scala background, like me, you may be tempted to believe that they are just like Java annotations (after all, they look the same) however do not be fooled by this similarity. Python annotations create new functions that replace the function that you just created.

So what does the @classmethod decorator do? Let me show you how I learned about it:

I had to modify an existing python module that looked like this:

def do_someting():
    data = getdata()
    return something(data)

def do_something_else():
    data = getdata()
    return something_else(data)

def getdata():
    return read_some_source()

My goal was to have the exact same transformations but with a new data source. That is, I wanted to add a new getdata() function.

My first instinct was to try to add the getdata() as a parameter of the other functions. This approach turned out to be unwieldy: now I had getdata all over the place in my code. There had to better way. That is when I bumped into the @classmethod decorator.

The @classmethod decorator

The @classmethod decorator, will shadow your function with another function that passes the current class as the first parameter to your function.

So for example the following code:

class One(object):

    @classmethod
    def class_method(cls, x):
        print "My class is: %s " %(cls) 

One.class_method(3)

Will print: My class is: <class '__main__.One'>

This means that your method, through the cls parameter, can access other fields from the class you are part of.

This becomes useful when, for example, you have a bunch of related methods and you want to shadow one of them (which was my case).

You can shadow one method by doing the following:

class One(object):

    @classmethod
    def do_someting(cls):
        data = cls.getdata()
        return something(data)

    @classmethod
    def getdata():
        return read_some_source()

class Another(One):

    @classmethod
    def getdata():
        return read_new_source()

With the help of @classmethod if you import One and you call do_something() you will get one data source. If you import Another and call do_something() you will get a new source.

Using the @classmethod decorator happily solved my problem without many code changes.

Summary

  • The @classmethod decorator allows you to have a reference to your enclosing class in your function, without the need of instantiating an object.
comments powered byDisqus