Python 实例方法、类方法与静态方法
说明 Python 中函数定义在类里后,为什么会变成实例方法、类方法或静态方法,以及三者各自绑定到谁。
#type / concept
#status / growing
#resource / python
#tech / lang / python
[!info] related notes
- 所属 MOC: Python 类与面向对象 MOC
- 前置概念: python类属性与实例属性
- 并列概念: python继承方法重写与super
- 易混淆概念: python函数与装饰器
- 关系笔记: python类与面向对象
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.namefrom_email是备用构造器,应该返回“当前类”的实例is_valid_name只做校验,不需要实例也不需要类
边界与易混淆点
@staticmethod不会自动获得面向对象能力;如果逻辑和类主题关系很弱,直接写成模块函数往往更清楚。@classmethod常被用作“多态构造器”;如果写死成User(...)而不是cls(...),子类继承时扩展性会变差。- 这三者的底层都和属性查找与描述符机制有关,但入门阶段先抓住“绑定上下文不同”就足够了。