[BangPypers] Classmethod, Decorators and staticmethod

Anand Balachandran Pillai abpillai at gmail.com
Fri Mar 6 15:23:00 CET 2009


On Fri, Mar 6, 2009 at 7:10 PM, Senthil Kumaran <orsenthil at gmail.com> wrote:
> On Thu, Mar 5, 2009 at 6:29 PM, VIJAY KUMAR <vnbang2003 at yahoo.com> wrote:
>>        Can some one please explain me with example about
>>        1) classmethod
>>        2) staticmethod
>>        3) Decorators
>

I will try to explain this the other way around, i.e starting with functions
and thinking of adding them to classes. I guess that offers a different
perspective to understanding static & class methods, decorators too.
It also tells you that there is nothing "special" about methods
in Python classes, they are just functions with some implicit
arguments.

Let us say you are the guy who truly believes in dynamic
creation of classes. You want to attach methods as you go along.
For this purpose, you define the simplest of classes.

>>> class C:pass
...

You want to populate this class with 3 methods, one
for adding, second for subtracting and third for multiplying
two numbers. While you do this, you also want to explore
the different possibilities of doing this.

First you define your "add" function.

>>> def add(a,b): return a + b
...

Pretty simple, right ? Now you are naive w.r.t Python and its classes,
and someone told you that in Python you can attach dynamic attributes
to almost anything, so you do this, which is very natural indeed.

>>> C.add = add

No problems there. Now you try to call it on the class C with
2 arguments.

>>> C.add(10,10)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method add() must be called with C instance as
first argument (got int instance instead)

Well, this is unexpected right ? The answer is yes, if you are unfamiliar with
Python instance methods, not otherwise. The issue if you call a function
on a Python class/instance, it should be either a class/instance method
respectively unless qualified otherwise.  And in Python ,instance methods
are called with an implicit "self" first argument, which must be
explicitly done by the
programmer when he defines the method.

However, you are adamant you don't want to change your function and still
call it on the class. How can this be done ?

This is where "staticmethod" helps you. It is somewhat similar to a C++ static
function in that there is only a single instance and it is not bound
to the class or
its instance. It is just "is", so this is best option for adding a
function to a class.

This is how you do it in Python.

>>> C.add = staticmethod(add)
Now,
>>> C.add(10,10)
20

Voila!

Now you are wiser about the secret machinations of Python classes, so you
wise up when you add the next function to the class as a method. Here is your
"subtract" method.

>>> def sub(self, a,b): print self;return a - b
...

Why the first "self" ? Because you are planning to add this as an instance
method to class "C"' and you have realized the hard way that Python implicitly
passes the instance to such methods.

Since this is an instance method, no cast is necessary.

>>> C.sub = sub

Now you create an instance of C and call "sub" on it.

>>> c=C()
>>> c.sub(20,10)
<__main__.C instance at 0x7ff1fcd1ef38>
10

All well, and that is good!

You are wise now, but not fully wise like the Python sage, so you think, "Hey,
why not try calling this on the class instead of the instance ? Since I have
added an explicit self, maybe it will work ?"

So you do this,

>>> C.sub(20, 10)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method sub() must be called with C instance as
first argument (got int instance instead)

Chaos results... This is because, since you are calling "sub" on the
class, not the instance
and it is not qualified as anything else, Python does not pass any
instance implicit argument to the method, instead calls it like a
static method. However the method expects the implicit instance
argument as first argument and hence the error.

How to resolve the problem while still keeping the function definition
the same ?
Answer: Make the function a classmethod.

Class methods are somewhere between static and instance methods. They
are similar
to static methods in that you can call them on the class as well as on
the instance, but
similar to instance methods in that like an instance method, Python passes the
class object implicitly to them, instead of the instance object.

So you wise up and do so for your next "mul" method.

>>> def mul(cls, a,b): print cls;return a * b
...

And you add it to your class as a "classmethod" like this,

>>> C.mul = classmethod(mul)

>>> C.mul(10,20)
__main__.C
200

However this can be called on the instance also. In this case, Python
makes sure it passes the instance's class as the first argument.

>>> c.mul(10,20)
__main__.C
200


As you can see, I added the "print" statements to see what is getting printed.
In "sub" it is the instance and in "mul" it is the class.

I am summarizing the 3 musketeers here.

1. Instance method - Associated to a class's instance. The instance
    object is passed as implicit first argument, which is often
denoted by "self". Can be
    called only on class instances.

2. Class method - Associated to the class. The class object is passed as
   implicit first argument, which is often denoted by "cls". Normally
called on class
   objects, but can be called on instances also in which case the
instance is automagically
   "downed" to the class.

3. Static method - Associated to none. The static method is like a
function living its
    life attaching itself to the class's name space, but it has no
loyalty towards either the
   class or its instances. It can be called on the class or its
instances. No implicit first
   argument is passed. This is the way to attach stand-alone functions
to a class.

Hope this is now ultra clear.. If you still are not clear, ping me and I will
let you know by 50K course details ;)

-Anand


More information about the BangPypers mailing list