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


当前回答

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

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

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

其他回答

staticmethod无法访问继承层次结构中对象、类或父类的属性。它可以直接在类中调用(无需创建对象)。

classmethod无法访问对象的属性。但是,它可以访问继承层次结构中的类和父类的属性。它可以直接在类中调用(无需创建对象)。如果在对象处调用,则它与不访问self的普通方法相同<属性>并访问self__第__类<属性>。

假设我们有一个b=2的类,我们将创建一个对象,并将其重新设置为b=4。Staticmethod无法访问以前的任何内容。Classmethod只能通过cls.b访问.b==2。正常方法可以通过self访问:.b==4和.b==2__第__.b类。

我们可以遵循KISS风格(保持简单,愚蠢):不要使用静态方法和类方法,不要在没有实例化它们的情况下使用类,只访问对象的属性self.attribute。有些语言是这样实现OOP的,我认为这不是坏主意

一个非常重要的实际差异发生在子类化时。如果你不介意的话,我会劫持@unsubu的例子:

class A: 
    def foo(self, x): 
        print("executing foo(%s, %s)" % (self, x)) 
 
    @classmethod
    def class_foo(cls, x): 
        print("executing class_foo(%s, %s)" % (cls, x))
 
    @staticmethod 
    def static_foo(x): 
        print("executing static_foo(%s)" % x)

class B(A):
    pass

在class_foo中,该方法知道它是在哪个类上调用的:

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

在static_foo中,无法确定它是在A还是B上调用的:

A.static_foo(1)
# => executing static_foo(1)
B.static_foo(1)
# => executing static_foo(1)

注意,这并不意味着您不能在静态方法中使用其他方法,您只需直接引用类,这意味着子类的静态方法仍将引用父类:

class A:
    @classmethod
    def class_qux(cls, x):
        print(f"executing class_qux({cls}, {x})")
    
    @classmethod
    def class_bar(cls, x):
        cls.class_qux(x)

    @staticmethod
    def static_bar(x):
        A.class_qux(x)

class B(A):
    pass

A.class_bar(1)
# => executing class_qux(<class '__main__.A'>, 1)
B.class_bar(1)
# => executing class_qux(<class '__main__.B'>, 1)
A.static_bar(1)
# => executing class_qux(<class '__main__.A'>, 1)
B.static_bar(1)
# => executing class_qux(<class '__main__.A'>, 1)

顾名思义,类方法用于更改类而不是对象。要对类进行更改,它们将修改类属性(而不是对象属性),因为这就是更新类的方式。这就是类方法将类(通常用“cls”表示)作为第一个参数的原因。

class A(object):
    m=54

    @classmethod
    def class_method(cls):
        print "m is %d" % cls.m

另一方面,静态方法用于执行未绑定到类的功能,即它们不会读取或写入类变量。因此,静态方法不将类作为参数。使用它们是为了使类可以执行与类的目的不直接相关的功能。

class X(object):
    m=54 #will not be referenced

    @staticmethod
    def static_method():
        print "Referencing/calling a variable or function outside this class. E.g. Some global variable/function."

@类方法:

可以通过cls和直接通过类名调用类变量和实例、类和静态方法,但不能通过实例变量。可以通过对象和类名直接调用。第一个参数需要cls,否则无法调用@classmethod,并且按照惯例使用cls的名称,因此其他名称而不是cls仍然有效。

@静态方法:

既可以由对象调用,也可以直接由类名调用。可以通过类名而不是实例变量直接调用类变量和实例、类和静态方法。不需要self或cls。

*在回答Python中什么是“实例方法”时,我还详细解释了实例方法?

@类方法:

例如,@classmethod可以通过cls和直接通过类名调用类变量和实例、类和静态方法,@classmethod可以通过对象和直接通过类名称调用,如下所示:

class Person:
    x = "Hello"
    def __init__(self, name):
        self.name = name
    
    @classmethod # Here
    def test1(cls):
        print(cls.x)   # Class variable by `cls`
        cls.test2(cls) # Instance method by `cls`
        cls.test3()    # Class method by `cls`
        cls.test4()    # Static method by `cls`
        print()
        print(Person.x)       # Class variable by class name
        Person.test2("Test2") # Instance method by class name
        Person.test3()        # Class method by class name
        Person.test4()        # Static method by class name
    
    def test2(self):
        print("Test2")
        
    @classmethod
    def test3(cls):
        print("Test3")
        
    @staticmethod
    def test4():
        print("Test4")

obj = Person("John")
obj.test1() # By object

# Or

Person.test1() # By class name

输出:

Hello
Test2
Test3
Test4

Hello
Test2
Test3
Test4

而且,@classmethod不能同时通过cls和直接通过类名调用实例变量,因此如果@classmethod试图同时通过cls和直接通过类名称调用实例变量(如下所示):

# ...
    
    @classmethod
    def test1(cls):
        print(cls.name) # Instance variable by `cls`
        
        # Or

        print(Person.name) # Instance variable by class name
# ...

obj = Person("John")
obj.test1()

# Or

Person.test1()

出现以下错误:

AttributeError:类型对象“Person”没有属性“name”

如果@classmethod没有cls:

# ...
    
    @classmethod
    def test1(): # Without "cls"
        print("Test1")
  
# ...

obj = Person("John")
obj.test1()

# Or

Person.test1()

@无法调用classmethod,则出现如下错误:

TypeError:test1()采用0个位置参数,但给出了1个

而且,cls的名称在约定中使用,因此其他名称而不是cls仍然有效,如下所示:

# ...

    @classmethod
    def test1(orange):
        print(orange.x)      # Class variable
        orange.test2(orange) # Instance method
        orange.test3()       # Class method
        orange.test4()       # Static method

# ...

obj = Person("John")
obj.test1()

# Or

Person.test1()

输出:

Hello
Test2
Test3
Test4

@静态方法:

例如,@staticmethod既可以按对象调用,也可以按类名直接调用,如下所示:

class Person:
    x = "Hello"
    def __init__(self, name):
        self.name = name

    @staticmethod # Here
    def test1():
        print("Test1")
    
    def test2(self):
        print("Test2")
        
    @classmethod
    def test3(cls):
        print("Test3")
        
    @staticmethod
    def test4():
        print("Test4")

obj = Person("John")
obj.test1() # By object

# Or

Person.test1() # By class name

输出:

Test1

而且,@staticmethod可以通过类名直接调用类变量和实例、类和静态方法,而不是实例变量,如下所示:

# ...
    
    @staticmethod
    def test1():
        print(Person.x)       # Class variable
        Person.test2("Test2") # Instance method
        Person.test3()        # Class method
        Person.test4()        # Static method
            
# ...

obj = Person("John")
obj.test1()

# Or

Person.test1()

输出:

Hello
Test2
Test3
Test4

并且,如果@staticmethod尝试调用实例变量,如下所示:

# ...
    
    @staticmethod
    def test1():
        print(Person.name) # Instance variable
            
# ...

obj = Person("John")
obj.test1()

# Or

Person.test1()

出现以下错误:

AttributeError:类型对象“Person”没有属性“name”

而且,@staticmethod不需要self或cls,因此如果@staticmmethod具有self或cl,则需要传递如下所示的参数:

# ...
    
    @staticmethod
    def test1(self): # With "self"
        print(self)

    # Or

    @staticmethod
    def test1(cls): # With "cls"
        print(cls)

# ...

obj = Person("John")
obj.test1("Test1") # With an argument

# Or

Person.test1("Test1") # With an argument

输出:

Test1

否则,如果不传递如下所示的参数:

# ...
    
    @staticmethod
    def test1(self): # With "self"
        print("Test1")

    # Or

    @staticmethod
    def test1(cls): # With "cls"
        print("Test1")

# ...

obj = Person("John")
obj.test1() # Without an argument

# Or

Person.test1() # Without an argument

出现以下错误:

TypeError:test1()缺少1个必需的位置参数:“self”

TypeError:test1()缺少1个必需的位置参数:“cls”

静态方法:

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

静态方法的优点:

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

类方法:

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