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


当前回答

从其文档中定义静态方法和类方法。以及何时使用静态方法和何时使用类方法。

静态方法类似于java和C#中的静态方法,它不会使用类的任何初始化值,只需要从外部进行操作即可。类方法:通常用于继承重写,当我们重写一个方法时,然后使用CLS实例来判断是否要调用子类或父类的方法。以防您希望同时使用同名和不同签名的方法。

静态方法(函数)->方法

Convert a function to be a static method.

A static method does not receive an implicit first argument.
To declare a static method, use this idiom:

     class C:
         @staticmethod
         def f(arg1, arg2, ...):
             ...

It can be called either on the class (e.g. C.f()) or on an instance
(e.g. C().f()).  The instance is ignored except for its class.

Static methods in Python are similar to those found in Java or C++.
For a more advanced concept, see the classmethod builtin.
"""

classmethod(函数)->方法

Convert a function to be a class method.

A class method receives the class as implicit first argument,
just like an instance method receives the instance.
To declare a class method, use this idiom:

  class C:
      @classmethod
      def f(cls, arg1, arg2, ...):
          ...

It can be called either on the class (e.g. C.f()) or on an instance
(e.g. C().f()).  The instance is ignored except for its class.
If a class method is called for a derived class, the derived class
object is passed as the implied first argument.

Class methods are different than C++ or Java static methods.
If you want those, see the staticmethod builtin.

其他回答

Python带有几个内置的装饰器。三大类是:

@classmethod
@staticmethod
@property

首先,让我们注意,类的任何函数都可以用这个类的实例调用(在初始化这个类之后)。

@classmethod是一种方法,它不仅可以作为类的实例调用函数,还可以直接由类本身作为其第一个参数调用函数。

@staticmethod是一种将函数放入类的方法(因为它在逻辑上属于类),同时表示它不需要访问类(因此我们不需要在函数定义中使用self)。

让我们考虑一下以下课程:

class DecoratorTest(object):

    def __init__(self):
        pass

    def doubler(self, x):
        return x*2

    @classmethod
    def class_doubler(cls, x): # we need to use 'cls' instead of 'self'; 'cls' reference to the class instead of an instance of the class
        return x*2

    @staticmethod
    def static_doubler(x): # no need adding 'self' here; static_doubler() could be just a function not inside the class
        return x*2

让我们看看它是如何工作的:

decor = DecoratorTest()

print(decor.doubler(5))
# 10

print(decor.class_doubler(5)) # a call with an instance of a class
# 10
print(DecoratorTest.class_doubler(5)) # a direct call by the class itself
# 10

# staticmethod could be called in the same way as classmethod.
print(decor.static_doubler(5)) # as an instance of the class
# 10
print(DecoratorTest.static_doubler(5)) # or as a direct call 
# 10

这里您可以看到这些方法的一些用例。

奖金:您可以在这里阅读@property decorator

分析@staticmethod,提供不同的见解。

类的普通方法是一种隐式动态方法,它将实例作为第一个参数。相反,静态方法不将实例作为第一个参数,因此称为“static”。

静态方法确实是一个与类定义之外的函数相同的正常函数。幸运的是,它被分组到类中,只是为了更接近应用它的位置,或者您可以滚动查找它。

让我先告诉一下用@classmethod修饰的方法和@staticmethod修饰的方法之间的相似性。

相似性:它们都可以在类本身上调用,而不仅仅是类的实例。所以,在某种意义上,这两种方法都是Class的方法。

区别:类方法将接收类本身作为第一个参数,而静态方法不接收。

因此,在某种意义上,静态方法并不绑定到类本身,只是因为它可能具有相关功能而挂在那里。

>>> class Klaus:
        @classmethod
        def classmthd(*args):
            return args

        @staticmethod
        def staticmthd(*args):
            return args

# 1. Call classmethod without any arg
>>> Klaus.classmthd()  
(__main__.Klaus,)  # the class gets passed as the first argument

# 2. Call classmethod with 1 arg
>>> Klaus.classmthd('chumma')
(__main__.Klaus, 'chumma')

# 3. Call staticmethod without any arg
>>> Klaus.staticmthd()  
()

# 4. Call staticmethod with 1 arg
>>> Klaus.staticmthd('chumma')
('chumma',)

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

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

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


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

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

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

静态方法用于将与类有某种逻辑联系的函数分组到该类。


foo只是一个函数,但当你调用.foo时,你不只是得到函数,您将得到函数的“部分应用”版本,其中对象实例a作为函数的第一个参数。foo需要2个参数,而a.foo只需要1个参数。

a绑定到foo。这就是以下术语“约束”的含义:

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

对于.class_foo,a不绑定到class_foo,而类a绑定到class-foo。

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

这里,对于staticmethod,即使它是一个方法,a.static_foo也只返回一个没有参数约束的好的ole函数。static_foo需要1个参数,并且.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函数只不过是在类中定义的函数。它可以在不首先实例化类的情况下调用。它的定义通过继承是不可变的。@classmethod函数也可以在不实例化类的情况下调用,但它的定义通过继承遵循子类,而不是父类。这是因为@classmethod函数的第一个参数必须始终是cls(class)。