实例方法必须带self参数,否则调用时会报TypeError;类方法用@classmethod装饰、参数为cls,适用于类级别操作和替代构造器;静态方法用@staticmethod装饰、无隐式参数,仅作命名空间归类的纯工具函数。

实例方法必须有 self,否则会报 TypeError: xxx() missing 1 required positional argument: 'self'
这是最常踩的坑:把实例方法当普通函数调用。Python 在调用实例方法时,会自动把当前实例对象作为第一个参数传进去,也就是 self。如果你手动创建类但没通过实例调用,比如 MyClass.method(),而 method 定义里写了 self,就会立刻报错。
正确做法是:要么通过实例调用(obj.method()),要么把方法改成类方法或静态方法。
- 实例方法适合操作实例数据,比如修改
self.name、调用其他实例方法 - 不能在类未实例化时使用,也不能被子类直接覆盖后安全调用父类逻辑(除非显式传入实例)
- 如果方法只读取类属性、不碰实例状态,却仍写成实例方法,会造成误导和潜在
self空值风险
@classmethod 的第一个参数是 cls,用于替代构造逻辑或访问类级别配置
类方法不是为了“省掉 self”而存在,而是明确表达“这个操作属于这个类本身,且可能依赖或修改类状态”。典型场景是替代构造器(alternative constructor):
class Date:
def __init__(self, year, month, day):
self.year = year
self.month = month
self.day = day
<pre class="brush:php;toolbar:false;">@classmethod
def from_string(cls, date_str):
year, month, day = map(int, date_str.split('-'))
return cls(year, month, day) # 注意这里用的是 cls,不是 Date
关键点:
-
cls是运行时真实的类(支持继承:子类调用from_string返回的也是子类实例) - 可读取/修改类变量(如
cls.counter += 1),但不能访问self.xxx - 不能直接访问实例属性或调用实例方法(没
self) - 常见误用:用
@classmethod包裹纯工具函数(无类依赖),这时该用@staticmethod
@staticmethod 就是“挂载在类里的普通函数”,和模块级函数行为一致
它既不接收 self,也不接收 cls,本质上就是个命名空间归类的工具函数。Python 解释器不会给它注入任何隐式参数。
适用场景很窄,但明确:
- 输入输出完全独立于类和实例(比如字符串格式校验、单位换算)
- 逻辑上属于该类的职责范畴,但不需要访问任何类或实例数据
- 想避免污染全局命名空间,又不想引入新模块
反例:
- 函数内部用了
Date.format_map—— 这说明它依赖类,应该用@classmethod - 函数里调用了
self.helper()—— 直接报错,也不是静态方法该干的事 - 函数只是简单加法
def add(a, b): return a + b却硬塞进类里 —— 没必要,放模块顶层更清晰
选哪个?看函数是否需要“知道它是谁”
判断链条很短:
- 要改/读实例数据 → 实例方法(带
self) - 要改/读类变量,或需返回当前类(含子类)的新实例 →
@classmethod(带cls) - 完全不依赖类名、类状态、实例状态 →
@staticmethod(无隐式参数)
最容易忽略的是:类方法在继承链中表现不同。比如 SubDate.from_string('2024-01-01') 返回的是 SubDate 实例,不是 Date;而静态方法做不到这点——它根本不知道自己在哪被调。这点在写可继承的工具类时特别关键。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











