When should I use @classmethod and when def method(self)?

marue picture marue · May 14, 2012 · Viewed 35.5k times · Source

While integrating a Django app I have not used before, I found two different ways used to define functions in classes. The author seems to use them both very intentionally. The first one is one I myself use a lot:

class Dummy(object):

    def some_function(self,*args,**kwargs):
        do something here
        self is the class instance

The other one is one I do not use, mostly because I do not understand when to use it, and what for:

class Dummy(object):

    @classmethod
    def some_function(cls,*args,**kwargs):
        do something here
        cls refers to what?

In the Python docs the classmethod decorator is explained with this sentence:

A class method receives the class as implicit first argument, just like an instance method receives the instance.

So I guess cls refers to Dummy itself (the class, not the instance). I do not exactly understand why this exists, because I could always do this:

type(self).do_something_with_the_class

Is this just for the sake of clarity, or did I miss the most important part: spooky and fascinating things that couldn't be done without it?

Answer

Marcin picture Marcin · May 14, 2012

Your guess is correct - you understand how classmethods work.

The why is that these methods can be called both on an instance OR on the class (in both cases, the class object will be passed as the first argument):

class Dummy(object):

    @classmethod
    def some_function(cls,*args,**kwargs):
        print cls

#both of these will have exactly the same effect
Dummy.some_function()
Dummy().some_function()

On the use of these on instances: There are at least two main uses for calling a classmethod on an instance:

  1. self.some_function() will call the version of some_function on the actual type of self, rather than the class in which that call happens to appear (and won't need attention if the class is renamed); and
  2. In cases where some_function is necessary to implement some protocol, but is useful to call on the class object alone.

The difference with staticmethod: There is another way of defining methods that don't access instance data, called staticmethod. That creates a method which does not receive an implicit first argument at all; accordingly it won't be passed any information about the instance or class on which it was called.

In [6]: class Foo(object): some_static = staticmethod(lambda x: x+1)

In [7]: Foo.some_static(1)
Out[7]: 2

In [8]: Foo().some_static(1)
Out[8]: 2

In [9]: class Bar(Foo): some_static = staticmethod(lambda x: x*2)

In [10]: Bar.some_static(1)
Out[10]: 2

In [11]: Bar().some_static(1)
Out[11]: 2

The main use I've found for it is to adapt an existing function (which doesn't expect to receive a self) to be a method on a class (or object).