用@staticmethod修饰的方法和用@classmethod修饰的方法有什么区别?


当前回答

@staticmethod只是禁用默认函数作为方法描述符。classmethod将函数包装在可调用的容器中,该容器将引用作为第一个参数传递给所属类:

>>> class C(object):
...  pass
... 
>>> def f():
...  pass
... 
>>> staticmethod(f).__get__(None, C)
<function f at 0x5c1cf0>
>>> classmethod(f).__get__(None, C)
<bound method type.f of <class '__main__.C'>>

事实上,classmethod有运行时开销,但可以访问所属的类。或者,我建议使用元类并将类方法放在元类上:

>>> class CMeta(type):
...  def foo(cls):
...   print cls
... 
>>> class C(object):
...  __metaclass__ = CMeta
... 
>>> C.foo()
<class '__main__.C'>

其他回答

静态方法:

没有自参数的简单函数。处理类属性;而不是实例属性。可以通过类和实例调用。内置函数staticmethod()用于创建它们。

静态方法的优点:

它在类作用域中本地化函数名它将功能代码移动到使用位置附近与模块级函数相比,导入更方便,因为不必专门导入每个方法@静态方法定义some_static_method(*args,**kwds):通过

类方法:

将第一个参数作为类名的函数。可以通过类和实例调用。这些是用内置函数中的classmethod创建的。@分类法定义some_class_method(cls,*args,**kwds):通过

这是一篇关于这个问题的短文

@staticmethod函数只不过是在类中定义的函数。它可以在不首先实例化类的情况下调用。它的定义通过继承是不可变的。@classmethod函数也可以在不实例化类的情况下调用,但它的定义通过继承遵循子类,而不是父类。这是因为@classmethod函数的第一个参数必须始终是cls(class)。

我想在前面所有答案的基础上补充以下内容,这不是官方的,但符合标准。

首先,你可以考虑总是给予最少的特权。因此,如果您不需要特定于实例的内容,请将其设置为类方法。如果您不需要特定于类的内容,请将其设置为静态方法。

第二件事是考虑您可以通过创建的方法类型进行通信。静态方法-助手函数意味着在类本身之外使用。类函数-可以在没有实例化的情况下调用,但意味着只能与该类一起使用-否则将是一个静态方法!实例方法-仅用于实例。

这可以帮助您沟通模式以及如何使用代码。

class Foo:
    @classmethod
    def bar(cls, id: int = None):
        query = session.query(
            a.id,
            a.name,
            a.address,
        )

        if id is not None:
            query = query.filter(a.id == id)

        return query

例如,上面提到的——没有理由说明方法栏不能是静态的。然而,通过将其设置为类方法,您可以传达它应该由类本身使用,而不是作为其他地方使用的助手函数!

请记住,以上内容不是官方的,而是我个人的偏好

我认为提供一个纯Python版本的staticmethod和classmethod将有助于在语言级别上理解它们之间的区别(请参阅Descriptor Howto Guide)。

这两个都是非数据描述符(如果您首先熟悉描述符,那么更容易理解它们)。

class StaticMethod(object):
    "Emulate PyStaticMethod_Type() in Objects/funcobject.c"

    def __init__(self, f):
        self.f = f

    def __get__(self, obj, objtype=None):
        return self.f


class ClassMethod(object):
    "Emulate PyClassMethod_Type() in Objects/funcobject.c"
    def __init__(self, f):
        self.f = f

    def __get__(self, obj, cls=None):
        def inner(*args, **kwargs):
            if cls is None:
                cls = type(obj)
            return self.f(cls, *args, **kwargs)
        return inner

类方法将类作为隐式第一参数接收,就像实例方法接收实例一样。它是一个绑定到类而不是类的对象的方法。它可以访问类的状态,因为它使用指向类而不是对象实例的类参数。它可以修改将应用于类的所有实例的类状态。例如,它可以修改将适用于所有实例的类变量。

另一方面,与类方法或实例方法相比,静态方法不接收隐式第一个参数。并且无法访问或修改类状态。它只属于类,因为从设计的角度来看,这是正确的方法。但就功能而言,在运行时,它并不与类绑定。

作为指导,使用静态方法作为实用程序,使用类方法作为工厂。或者可以定义一个单例。并使用实例方法对实例的状态和行为进行建模。

希望我清楚!