协慌网

登录 贡献 社区

@staticmethod 和 @classmethod 有什么区别?

答案

也许一些示例代码会有所帮助:注意fooclass_foostatic_foo的调用签名的static_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)

使用 classmethods ,对象实例的类隐式传递为第一个参数而不是self

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

您也可以使用该类调用class_foo 。实际上,如果您将某些东西定义为类方法,那可能是因为您打算从类而不是类实例中调用它。 A.foo(1)会引发一个 TypeError,但是A.class_foo(1)工作正常:

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

人们发现类方法的一个用途是创建可继承的替代构造函数


对于 staticmethodsself (对象实例)和cls (类)都不会作为第一个参数隐式传递。它们的行为类似于普通函数,除了您可以从实例或类中调用它们:

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

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

Staticmethod 用于将与类有逻辑连接的函数分组到类中。


foo仅仅是一个函数,但是当你调用a.foo你不只是得到的功能,你会得到一个 “部分应用” 功能与对象实例的版本a绑定作为第一个参数的函数。 foo需要 2 个参数,而a.foo只需要 1 个参数。

afoo 。这就是下面的 “绑定” 一词的含义:

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

使用a.class_fooa不绑定到class_foo ,而是将类A绑定到class_foo

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

在这里,使用a.static_foo方法,即使它是一个方法, a.static_foo只返回一个没有参数绑定的良好'ole 函数。 static_foo需要 1 个参数,而a.static_foo需要 1 个参数。

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

当然,当你用类A调用static_foo时会发生同样的事情。

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

staticmethod是一种对调用它的类或实例一无所知的方法。它只是获取传递的参数,没有隐含的第一个参数。它在 Python 中基本没用 - 您可以使用模块函数而不是静态方法。

类方法 ,在另一方面,是获取传递的类,它被称为上,或该类的实例,它被称为上的,作为第一个参数的方法。当您希望该方法成为该类的工厂时,这很有用:因为它获取了作为第一个参数调用的实际类,所以即使涉及子类,也可以始终实例化正确的类。例如,观察dict.fromkeys()在子类上调用时如何返回子类的实例:

>>> class DictSubclass(dict):
...     def __repr__(self):
...         return "DictSubclass"
... 
>>> dict.fromkeys("abc")
{'a': None, 'c': None, 'b': None}
>>> DictSubclass.fromkeys("abc")
DictSubclass
>>>

基本上@classmethod创建了一个方法,其第一个参数是从中调用的类(而不是类实例), @staticmethod没有任何隐式参数。