@staticmethod 和 @classmethod 之间的区别

新手上路,请多包涵
阅读 579
2 个回答

也许一些示例代码会有所帮助:注意 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)


使用 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)

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


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

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

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

With a.class_foo , a is not bound to class_foo , rather the class A is bound to class_foo .

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

在这里,使用静态方法,即使它是一个方法, 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>

原文由 unutbu 发布,翻译遵循 CC BY-SA 4.0 许可协议

静态 方法是一种对调用它的类或实例一无所知的方法。它只是获取传递的参数,没有隐式的第一个参数。它在 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
>>>

原文由 Thomas Wouters 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题