Python 实例方法、类方法与静态方法

说明 Python 中函数定义在类里后,为什么会变成实例方法、类方法或静态方法,以及三者各自绑定到谁。

#type / concept #status / growing #resource / python #tech / lang / python

[!info] related notes

Python 实例方法、类方法与静态方法

一句话定义

同样是写在类体里的函数,Python 会根据是否经过 @classmethod@staticmethod 包装,决定调用时自动绑定实例、绑定类,还是完全不做绑定。

核心机制 / 工作原理

1. 普通函数放进类里后,访问时会发生方法绑定

最常见的实例方法本质上还是定义在类上的函数,但当你通过实例访问它时,Python 会把当前实例自动塞进第一个参数,所以我们约定把它写成 self

class User:
    def greet(self):
        return f"hello {self.name}"

u.greet() 实际等价于“把 u 绑定进去再调用”,所以实例方法天然适合操作实例状态。

2. @classmethod 绑定的是类,不是实例

类方法会把“当前类对象”作为第一个参数,约定名为 cls。它适合:

  • 访问或修改类级配置
  • 写备用构造器
  • 让子类继承时保留多态性

因为 cls 指向“当前调用时的类”,所以子类调用类方法时会拿到子类自己,而不是写死父类。

3. @staticmethod 不自动绑定任何对象

静态方法只是把函数挂在类名空间下,便于从语义上表达“这个工具函数和这个类主题有关”。它:

  • 不接收 self
  • 不接收 cls
  • 调用时和普通函数几乎一样

4. 三者差异的本质是“调用时自动注入什么上下文”

  • 实例方法:注入实例
  • 类方法:注入类
  • 静态方法:不注入

所以不要死记“语法三件套”,而要先问:这个行为到底需要实例状态、类级状态,还是根本不需要上下文。

最小例子 / 最小场景

class User:
    platform = "web"

    def __init__(self, name: str):
        self.name = name

    def greet(self):
        return f"hello {self.name}"

    @classmethod
    def from_email(cls, email: str):
        name = email.split("@")[0]
        return cls(name)

    @staticmethod
    def is_valid_name(name: str) -> bool:
        return len(name) >= 2


u = User.from_email("alice@example.com")
print(u.greet())                 # hello alice
print(User.platform)             # web
print(User.is_valid_name("Al"))  # True

这个例子里:

  • greet 依赖实例状态 self.name
  • from_email 是备用构造器,应该返回“当前类”的实例
  • is_valid_name 只做校验,不需要实例也不需要类

边界与易混淆点

  1. @staticmethod 不会自动获得面向对象能力;如果逻辑和类主题关系很弱,直接写成模块函数往往更清楚。
  2. @classmethod 常被用作“多态构造器”;如果写死成 User(...) 而不是 cls(...),子类继承时扩展性会变差。
  3. 这三者的底层都和属性查找与描述符机制有关,但入门阶段先抓住“绑定上下文不同”就足够了。
创建于 2026/5/20 更新于 2026/5/27