跳转至

14. Python中@staticmethod与@classmethod的区别

题目

@staticmethod 和被 @classmethod装饰的函数有什么区别? 链接

回答一

写点例子助于理解,注意对foo调用的区别。 class_foostatic_foo

class A(object):
    def foo(self,x):
        print "executing foo(%s,%s)"%(self,x)

    @classmethod
    def class_foo(cls,x):
        print "executing class_foo(%s,%s)"%(cls,x)

    @staticmethod
    def static_foo(x):
        print "executing static_foo(%s)"%x

a=A()

下面是一个实例对象调用一个方法的通常方式,实例对象a隐式地被当做第一个参数传入。

a.foo(1)
# executing foo(<__main__.A object at 0xb7dbef0c>,1)

使用类方法(classmethod),实例对象的class隐式地被当做第一个参数传入。

a.class_foo(1)
# executing class_foo(<class '__main__.A'>,1)

你也你能使用class去调用class_foo,如果你定义了某个方法为类方法(classmethod),很可能你想通过类去调用它而非通过类实例。A.foo(1)将会引发类型错误(TypeError),但是A.class_foo(1)是OK的。

A.class_foo(1)
# executing class_foo(<class '__main__.A'>,1)

使用类方法的一种场景是创建可继承的替代构造函数。

使用静态方法(staticmethod), self(实例)和cls(类)都不会被隐式地当做第一个参数传入。除了通过一个实例或者类来调用以外,这类方法表现和普通的函数无异。

a.static_foo(1)
# executing static_foo(1)

A.static_foo('hi')
# executing static_foo(hi)

静态方法用来聚合一些和类有逻辑关系的一些方法。

foo是一个函数,但是当你调用a.foo时并没有得到这个函数,而是获得了该函数的“部分应用(partially applied)”版本,并将对象实例绑定为该函数的第一个参数。foo需传入2个参数,但是a.foo仅需传入一个参数。

a被绑定到foo,如下

print(a.foo)
# <bound method A.foo of <__main__.A object at 0xb7d52f0c>>

a.class_fooa并没有绑定到class_foo,而是 class A绑定到class_foo

print(a.class_foo)
# <bound method type.class_foo of <class '__main__.A'>>

对于staticmethod,即使这是一个方法,a.static_foo仅返回没有任何参数绑定的函数。static_foo要求传入1个参数,a.static_foo同样要求传入一个参数。

print(a.static_foo)
# <function static_foo at 0xb7d479cc>

当然,你使用class A去调用static_foo时也一样。

print(A.static_foo)
# <function static_foo at 0xb7d479cc>