python:classmethod在这段代码中做什么?

在django.utils.tree.py:

1
2
3
4
5
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)

我不知道classmethod在这个代码示例中做了什么。谁能解释一下它是做什么的,怎么用的?


classmethod是一个描述符,封装了一个函数,你可以在一个类上调用结果对象,或者(等价地)调用它的一个实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
>>> 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'>,)

正如您所看到的,无论您是直接定义它还是使用装饰器语法定义它,无论您是对类还是实例调用它,classmethod总是将类作为它的第一个参数接收。

classmethod的主要用途之一是定义"可选构造函数":

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
>>> 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')

现在如果你子类化y,类方法会继续工作,例如:

1
2
3
4
5
6
7
>>> class k(y):
...   def __repr__(self):
...     return 'k(%r)' % self.s.upper()
...
>>> k1 = k.fromlist(['za','bu'])
>>> k1
k('ZA,BU')


它使调用类上的方法而不是对象成为可能:

1
2
3
4
5
6
class MyClass(object):
    def _new_instance(cls, blah):
        pass
    _new_instance = classmethod(_new_instance)

MyClass._new_instance("blah")