Python 中 @staticmethod 和 @classmethod 之间的区别

Python @classmethod@staticmethod的区别

@staticmethod 修饰的函数和用@classmethod 修饰的函数有什么区别?

下面的示例代码会对理解二者的区别有所帮助:注意调用foo,class_foo和static_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)Code language: CSS (css)

使用 classmethods,对象实例的类作为第一个参数而不是self.

a.class_foo(1)
# executing class_foo(<class '__main__.A'>, 1)Code language: PHP (php)

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

A.class_foo(1)
# executing class_foo(<class '__main__.A'>, 1)Code language: PHP (php)

classmethod的一种用途是创建可继承的替代构造函数。

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

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

A.static_foo('hi')
# executing static_foo(hi)Code language: PHP (php)

staticmethod用于对与类与类有某种逻辑联系的函数进行分组。

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

print(a.foo)
# <bound method A.foo of <__main__.A object at 0xb7d52f0c>>Code language: PHP (php)

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

print(a.class_foo)
# <bound method type.class_foo of <class '__main__.A'>>Code language: PHP (php)

在这里,使用staticmethod,即使它是一个方法 ,static_foo需要 1 个参数, a.static_foo也需要 1 个参数。

print(a.static_foo)
# <function static_foo at 0xb7d479cc>Code language: PHP (php)

当然,当改为static_foo与类通信时,也会发生同样的事情A。

print(A.static_foo)
# <function static_foo at 0xb7d479cc>Code language: PHP (php)

staticmethod是一种对调用它的类或实例一无所知的方法。

它只获取传递的参数,没有隐式的第一个参数。它在 Python 中基本上没用——你可以只使用模块函数而不是staticmethod。

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

class DictSubclass(dict):
… def repr(self):
… return “DictSubclass”

dict.fromkeys(“abc”)
{‘a’: None, ‘c’: None, ‘b’: None}
DictSubclass.fromkeys(“abc”)
DictSubclass

发表评论