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.