70

In django.utils.tree.py:

def _new_instance(cls, children=None, connector=None, negated=False):
    obj = Node(children, connector, negated)
    obj.__class__ = cls
    return obj
_new_instance = classmethod(_new_instance)

I don't know what classmethod does in this code sample. Can someone explain what it does and how to use it?

CrazyChucky
  • 3,263
  • 4
  • 11
  • 25
zjm1126
  • 63,397
  • 81
  • 173
  • 221

2 Answers2

218

classmethod is a decorator, wrapping a function, and you can call the resulting object on a class or (equivalently) an instance thereof:

>>> class x(object):
...   def c1(*args): print 'c1', args
...   c1 = classmethod(c1)
...   @classmethod
...   def c2(*args): print 'c2', args
... 
>>> inst = x()
>>> x.c1()
c1 (<class '__main__.x'>,)
>>> x.c2()
c2 (<class '__main__.x'>,)
>>> inst.c1()
c1 (<class '__main__.x'>,)
>>> inst.c2()
c2 (<class '__main__.x'>,)

As you see, whether you define it directly or with decorator syntax, and whether you call it on the class or the instance, the classmethod always receives the class as its first argument.

One of the main uses of classmethod is to define alternative constructors:

>>> class y(object):
...   def __init__(self, astring):
...     self.s = astring
...   @classmethod
...   def fromlist(cls, alist):
...     x = cls('')
...     x.s = ','.join(str(s) for s in alist)
...     return x
...   def __repr__(self):
...     return 'y(%r)' % self.s
...
>>> y1 = y('xx')
>>> y1
y('xx')
>>> y2 = y.fromlist(range(3))
>>> y2
y('0,1,2')

Now if you subclass y, the classmethod keeps working, e.g.:

>>> class k(y):
...   def __repr__(self):
...     return 'k(%r)' % self.s.upper()
...
>>> k1 = k.fromlist(['za','bu'])
>>> k1
k('ZA,BU')
Tobias Feil
  • 2,399
  • 3
  • 25
  • 41
Alex Martelli
  • 854,459
  • 170
  • 1,222
  • 1,395
  • 33
    This isn't an altenative constructor, this is a factory method. – t3chb0t Feb 12 '18 at 18:58
  • 8
    @t3chb0t it is a factory method that works as an alternative constructor. – Yasir Jan May 15 '19 at 08:59
  • 2
    Agreed with @t3chb0t, this is an alternative [string representation of the object](https://docs.python.org/3/reference/datamodel.html#object.__repr__). Objects of class y and k in this example appear to have the same construction. – Mark Aug 24 '21 at 19:08
9

It makes it possible to call the method on the class instead of an object:

class MyClass(object):
    def _new_instance(cls, blah):
        pass
    _new_instance = classmethod(_new_instance)

MyClass._new_instance("blah")
Ned Batchelder
  • 364,293
  • 75
  • 561
  • 662