Skip to content

Python 静态方法(@staticmethod

静态方法是定义在类体内部的函数,用 @staticmethod 标记。调用时不会自动传入 self(实例)cls(类),因此不绑定某一具体实例或类对象。

  • 仍可通过 类名.静态方法(...)实例.静态方法(...) 调用(后者不会把实例当作第一个参数传入)。
  • 若需要读类属性实例属性,必须在方法内显式类名.属性 或把对象作为参数传入;不能像实例方法那样依赖 self.x,也不能像类方法那样依赖 cls.x

适合把与类概念相关、但逻辑上不依赖实例状态的工具函数收拢在类命名空间下,便于组织代码(与模块级函数相比,多了一层「归属」)。与 类与对象self 变量 对照阅读更清晰。

为什么需要静态方法?

例如把字符串、列表、元组相关的工具按主题放进不同类,命名空间更清晰:

python
class ListUtils:
    @staticmethod
    def reverse(lst):
        return lst[::-1]

    @staticmethod
    def clear(lst):
        lst.clear()


class StringUtils:
    @staticmethod
    def reverse(s):
        return s[::-1]

    @staticmethod
    def upper(s):
        return str(s).upper()

需要时调用 ListUtils.reverse(...)StringUtils.upper(...) 即可。若逻辑与类完全无关,用模块级函数同样合理,按团队风格选择。

两种写法

1. 装饰器 @staticmethod(推荐)

python
class MathUtils:
    @staticmethod
    def multiply(a, b):
        return a * b


print(MathUtils.multiply(10, 5))  # 50

2. 内置函数 staticmethod(...)

把普通函数包装后赋给类属性,效果类似:

python
class StringUtils:
    def to_uppercase(s):
        return str(s).upper()


StringUtils.upper = staticmethod(StringUtils.to_uppercase)
print(StringUtils.upper("Python"))  # PYTHON

若把 to_uppercase 当成实例方法去调用(未加 staticmethod),解释器会传入 self,容易出现「多传了一个参数」的错误:

python
su = StringUtils()
try:
    print(su.to_uppercase("Python"))
except TypeError as e:
    print(e)  # takes 1 positional argument but 2 were given

未包装时,从类名直接调用 StringUtils.to_uppercase("Python") 可以,因为只传入一个参数。

静态方法、类方法、实例方法对比

实例方法类方法 @classmethod静态方法 @staticmethod
第一个参数self(实例)cls(类)无默认绑定
典型用途读写实例状态工厂方法、需要类对象本身逻辑放在类下但不依赖 self/cls
访问实例属性self.x需先有实例或显式传入须通过参数或其它方式
访问类属性类名.xself.x(查找链)cls.x类名.x(显式)

示例:

python
class Test:
    x = 10

    @classmethod
    def foo(cls):
        print(cls.x)

    @staticmethod
    def bar():
        print(Test.x)  # 须写类名;不能写未限定的 x


Test.foo()
Test.bar()

输出:

text
10
10

实例方法需要 self,可访问绑定到该实例的属性及类属性(按查找规则):

python
class Test:
    x = 10

    def func(self):
        print(type(self))
        print(self.x)

小结

  • @staticmethod:不自动接收 self / cls,更像挂在类上的普通函数
  • 需要类或实例时,用类名参数或改用 @classmethod / 实例方法
  • 日常优先用装饰器语法;staticmethod(...) 多用于动态挂载等少见场景。

参考