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


当前回答

基本上,@classmethod生成的方法的第一个参数是从中调用的类(而不是类实例),@staticmethod没有任何隐式参数。

其他回答

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

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

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

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

首先,让我们从一个示例代码开始,我们将使用它来理解这两个概念:

class Employee:

    NO_OF_EMPLOYEES = 0
  
    def __init__(self, first_name, last_name, salary):
        self.first_name = first_name
        self.last_name = last_name
        self.salary = salary
        self.increment_employees()

    def give_raise(self, amount):
        self.salary += amount

    @classmethod
    def employee_from_full_name(cls, full_name, salary):
        split_name = full_name.split(' ')
        first_name = split_name[0]
        last_name = split_name[1]
        return cls(first_name, last_name, salary)

    @classmethod
    def increment_employees(cls):
        cls.NO_OF_EMPLOYEES += 1

    @staticmethod
    def get_employee_legal_obligations_txt():
        legal_obligations = """
        1. An employee must complete 8 hours per working day
        2. ...
        """
        return legal_obligations

Class方法

类方法接受类本身作为隐式参数,以及(可选地)定义中指定的任何其他参数。重要的是要理解类方法不能访问对象实例(就像实例方法一样)。因此,类方法不能用于更改实例化对象的状态,而是能够更改该类的所有实例之间共享的类状态。当我们需要访问类本身时,类方法通常很有用——例如,当我们想要创建工厂方法时,即创建类实例的方法。换句话说,类方法可以作为替代构造函数。

在我们的示例代码中,可以通过提供三个参数来构造Employee的实例;first_name、last_name和薪水。

employee_1 = Employee('Andrew', 'Brown', 85000)
print(employee_1.first_name)
print(employee_1.salary)

'Andrew'
85000

现在,让我们假设有可能在单个字段中提供雇员的姓名,在该字段中,名字和姓氏用空格分隔。在本例中,我们可以使用名为employee_from_full_name的类方法,该方法总共接受三个参数。第一个是类本身,这是一个隐式参数,这意味着在调用方法时不会提供它-Python将自动为我们执行此操作:

employee_2 = Employee.employee_from_full_name('John Black', 95000)
print(employee_2.first_name)
print(employee_2.salary)

'John'
95000

请注意,也可以从对象实例调用employee_from_full_name,尽管在这种情况下,这没有什么意义:

employee_1 = Employee('Andrew', 'Brown', 85000)
employee_2 = employee_1.employee_from_full_name('John Black', 95000)

我们可能想要创建类方法的另一个原因是,当我们需要更改类的状态时。在我们的示例中,类变量NO_OF_EMPLOYEES跟踪当前为公司工作的员工数量。每次创建Employee的新实例时都会调用此方法,并相应地更新计数:

employee_1 = Employee('Andrew', 'Brown', 85000)
print(f'Number of employees: {Employee.NO_OF_EMPLOYEES}')
employee_2 = Employee.employee_from_full_name('John Black', 95000)
print(f'Number of employees: {Employee.NO_OF_EMPLOYEES}')

Number of employees: 1
Number of employees: 2

静态方法

另一方面,在静态方法中,实例(即self)和类本身(即cls)都不会作为隐式参数传递。这意味着此类方法不能访问类本身或其实例。现在有人可能会争辩说,静态方法在类的上下文中并不有用,因为它们也可以放在助手模块中,而不是作为类的成员添加它们。在面向对象的编程中,将类构造成逻辑块非常重要,因此,当我们需要在类下添加方法时,静态方法非常有用,因为它在逻辑上属于该类。在我们的示例中,名为get_eemployee_legal_entributions_txt的静态方法只返回一个字符串,该字符串包含公司每个员工的法律义务。此函数不与类本身或任何实例交互。它可能被放置在不同的帮助器模块中,但是,它只与这个类相关,因此我们必须将它放置在Employee类下。

可以直接从类本身访问静态方法

print(Employee.get_employee_legal_obligations_txt())


    1. An employee must complete 8 hours per working day
    2. ...

或从类的实例:

employee_1 = Employee('Andrew', 'Brown', 85000)
print(employee_1.get_employee_legal_obligations_txt())


    1. An employee must complete 8 hours per working day
    2. ...

工具书类

Python中静态方法和类方法的区别是什么?

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

静态方法类似于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.

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

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

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

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

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