@staticmethod和@classmethod的区别

2022-09-05 00:41:00

@staticmethod装饰的功能和用@classmethod装饰的功能有什么区别?


答案 1

也许一些示例代码会有所帮助:请注意 和 的调用签名的差异:fooclass_foostatic_foo

class A(object):
    def foo(self, x):
        print(f"executing foo({self}, {x})")

    @classmethod
    def class_foo(cls, x):
        print(f"executing class_foo({cls}, {x})")

    @staticmethod
    def static_foo(x):
        print(f"executing static_foo({x})")

a = A()

以下是对象实例调用方法的常用方式。对象实例 , 作为第一个参数隐式传递。a

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

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

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

您也可以使用该类进行调用。事实上,如果你将某些东西定义为类方法,那可能是因为你打算从类而不是从类实例调用它。 会提出一个TypeError,但工作得很好:class_fooA.foo(1)A.class_foo(1)

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

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


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

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

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

静态方法用于对函数进行分组,这些函数与类具有某种逻辑连接。


foo只是一个函数,但是当您调用时,您不仅会获取该函数,还会获得该函数的“部分应用”版本,其中对象实例绑定为函数的第一个参数。 需要 2 个参数,而只期望 1 个参数。a.fooafooa.foo

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

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

with ,不绑定到 ,而是类绑定到 。a.class_fooaclass_fooAclass_foo

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

在这里,使用静态方法,即使它是一个方法,也只是返回一个没有参数绑定的良好'ole函数。 期望 1 个参数,也期望 1 个参数。a.static_foostatic_fooa.static_foo

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

当然,当你打电话给班级时,也会发生同样的事情。static_fooA

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

答案 2

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

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

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