关于静态方法:python中的@staticmethod有什么意义?

What's the point of @staticmethod in Python?

为了更好地理解静态方法在Python中的工作方式,我开发了这个简短的测试/示例代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class TestClass:
    def __init__(self, size):
        self.size = size

    def instance(self):
        print("regular instance method - with 'self'")

    @staticmethod
    def static():
        print("static instance method - with @staticmethod")

    def static_class():
        print("static class method")


a = TestClass(1000)

a.instance()
a.static()
TestClass.static_class()

此代码工作正常,不会返回任何错误。我的问题是:

  • 我是否正确地理解"self"可以理解为"这个方法将从实例中调用"?

  • 再说一遍,@staticmethod背后的逻辑是什么-是创建可以从实例调用的静态方法吗?这不正是静态方法的意义吗?

  • 为什么第二种方法比第三种方法更受欢迎?(我假设由于存在装饰器,所以有一点需要说明。)第三个选项似乎更简单、更直接。


  • 这是一篇关于静态方法的文章。综上所述:

    • 实例方法:需要实例作为第一个参数
    • 类方法:要求类作为第一个参数
    • 静态方法:不需要作为第一个参数

    关于你的问题:

  • 对。虽然变量名self是一种约定,但它属于实例。
  • 静态方法可用于将类似的实用方法分组到同一类下。
  • 对于类中的方法,您要么需要将self添加为第一个参数,要么用@staticmethod修饰该方法。"没有参数的非修饰方法将导致错误。
  • 当用参数调用时,可以更清楚地看到这些是如何工作的。修改后的示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    class TestClass:

        weight = 200                             # class attr

        def __init__(self, size):
            self.size = size                     # instance attr

        def instance_mthd(self, val):
            print("Instance method, with 'self':", self.size*val)

        @classmethod
        def class_mthd(cls, val):
            print("Class method, with `cls`:", cls.weight*val)

        @staticmethod
        def static_mthd(val):
            print("Static method, with neither args:", val)

    a = TestClass(1000)

    a.instance_mthd(2)
    # Instance method, with 'self': 2000

    TestClass.class_mthd(2)
    # Class method, with `cls`: 400

    a.static_mthd(2)
    # Static method, with neither args: 2

    总的来说,您可以从访问的角度考虑每个方法:

    • 如果需要访问实例或实例组件(例如实例属性),请使用实例方法,因为它将self作为第一个参数传递。
    • 同样,如果需要访问类,请使用类方法。
    • 如果对实例和类的访问都不重要,则可以使用静态方法。

    注意,在上面的示例中,每个方法类型都传递相同的参数,但是通过selfcls对实例和类属性的访问不同。

    注意,有一种方法可以使用self.__class__从实例方法访问类组件,从而避免了对类方法的需要:

    1
    2
    3
    4
    5
    6
    7
    8
        ...

        def instance_mthd2(self, val):
            print("Instance method, with class access via `self`:", self.__class__.weight*val)
        ...

    a.instance_mthd2(2)
    # Instance method, with class access via `self`: 400

    参考:我建议看RaymondHettinger的Talkpython的类开发工具包,它用示例清楚地阐明了每种方法类型的用途。


    方法作用于调用它们的实例。实例作为第一个参数传递,通常称为self

    类方法类似,但作用于整个类对象,而不是其中一个实例。它们作为构造函数和工厂函数,或者配置设置和其他同时影响类或其所有实例的情况,而不是单个实例,都非常方便。

    第三个选项,静态方法,是奇数。它们既不传递实例也不传递类。它们有利于在程序的类结构中为组织目的嵌套实用程序功能,但在某种方式上(对代码审阅者、"linting"和程序检查工具等)明确表示您有意不依赖实例或类值。这样,就不会得到关于未使用的self的"已声明但从未使用的变量"警告。

    从调用者的角度来看,静态方法与任何其他方法调用类似。如果您没有可用的@staticmethod,那么您可以使用一个普通的实例或类方法(尽管可能存在过量"变量未使用"的风险)。!"过梁警告)。因此,与类方法不同,静态方法是Python的一个完全可选的部分。它们不向语言添加任何功能;相反,它们提供了一种使开发人员的意图更清晰的方法。


    以下是您问题的答案:

    问题1:

    Do I understand correctly that"self" can be understood as something like"this method will be called from an instance"?

    不,那不完全是Trueself表示函数的第一个参数应该是类的实例。例如:

    1
    def my_class_function(self)

    可以称为:

    1
    2
    3
    self.my_class_function()
    OR,
    my_class_function(self)

    此外,不必使用self作为对类的对象的引用。您可以使用任何东西(只要它是有效变量),但是使用self是所有地方都遵循的标准。

    问题2:

    Then again, what's the logic behind @staticmethod - is it to create static methods which can be called from an instance? Isn't that exactly not what static methods are about?

    @staticmethod变量用于函数中不需要引用类对象的函数,即不使用self访问类的任何属性或函数。

    问题3:

    Why would the second approach be favored over the third one? (I assume that since the decorator exists, there is a point to this.) The 3rd option seems to be the simpler and more straightforward.

    使用第二种方法,即使用@staticmetod,您可以使用类的对象从类外部调用函数,而不像使用第三种方法(不使用decorator),因为函数的范围在类内。