在Python的面向对象编程里,实例方法第一个参数self常常让初学者困惑。它既不是语言保留字,也不是自动声明的变量,而是靠约定存在的形参,背后关联着描述器与绑定调用的整套机制。

self的基本行为与调用原理
当我们定义一个类并在其中写实例方法时,方法表面上看只声明了除self外的参数,但实际通过实例调用时,解释器会把调用者本身塞进self。这个过程由函数的__get__描述器完成:函数对象在类里被访问时返回一个绑定方法,绑定方法已经把实例固定为第一个参数。
下面这段代码展示了同样的加法逻辑,分别用实例调用和类调用,结果差异很明显:
class Counter:
def __init__(self, value):
self.value = value
def add(self, n):
self.value += n
return self.value
c = Counter(10)
# 实例调用,self自动绑定为c
print(c.add(5)) # 输出15
# 类调用,必须手动传实例
print(Counter.add(c, 3)) # 输出18
可以看到,c.add(5)等价于Counter.add(c, 5)。如果直接写Counter.add(5),解释器会抱怨缺少位置参数,因为此时没有对象能填进self。这种绑定机制让方法天然知道操作的是哪一个具体对象。
self在方法内部能做什么
self的核心价值是给方法一个访问当前实例状态的入口。通过self,我们既能读已有属性,也能在运行中动态挂载新属性,还可以调用同实例的其他方法,形成协作。
以下示例里,save方法借助self读取name与data,并调用_write做落盘动作,体现出self串联实例行为的作用:
class Store:
def __init__(self, name):
self.name = name
self.data = []
def add_item(self, item):
self.data.append(item)
# 通过self调用另一实例方法
self._log('add')
def _log(self, action):
print(self.name + ' ' + action)
def save(self):
self._write(self.name, self.data)
def _write(self, n, d):
print('write ' + n + ':' + str(d))
s = Store('cache')
s.add_item(1)
s.save()
若把self改名成this或者obj,代码依然能跑,因为Python只认位置,不认名字。但社区约定使用self,是为了让阅读者一眼明白这是实例方法。反之,如果在方法里遗漏self参数,该方法就变成普通函数,无法访问实例,也容易被误用为静态逻辑。
self与类方法、静态方法的对照
理解了self,就能分清三类方法的边界。@classmethod的第一个参数是cls,接收类本身;@staticmethod则没有任何自动传入的参数。它们都不依赖self所代表的实例状态。
| 方法类型 | 首参数 | 调用者 | 能否用self |
|---|---|---|---|
| 实例方法 | self | 实例或类+实例 | 能 |
| 类方法 | cls | 类或实例 | 不能 |
| 静态方法 | 无 | 类或实例 | 不能 |
下面代码演示三者在同一个类中的写法,注意实例方法必须通过实例才能自然使用self:
class Demo:
rate = 0.1
def inst(self, x):
return x + 1
@classmethod
def cls_m(cls, x):
return x * cls.rate
@staticmethod
def st_m(x):
return x - 1
d = Demo()
print(d.inst(2))
print(Demo.cls_m(10))
print(Demo.st_m(10))
在继承场景里,self还承担着多态的载体角色。子类实例调用父类定义的实例方法时,self指向的还是子类对象,因此方法内通过self访问的属性可能已被子类覆盖,这种动态绑定是Python灵活性的来源,但也要求开发者清楚当前self的真实类型。
常见误用与规避
一种典型错误是在实例方法内部又创建了同名局部变量,却以为改的是self属性。如下面这样写,value只是函数里的普通变量,实例的self.value并未变化:
class Bug:
def __init__(self):
self.value = 0
def wrong(self):
value = 10
# 这里并没有修改self.value
return value
def right(self):
self.value = 10
return self.value
b = Bug()
print(b.wrong()) # 10
print(b.value) # 0
print(b.right()) # 10
print(b.value) # 10
另一个坑是在类体外把实例方法赋值给变量后丢失绑定。例如f = Demo.inst得到的是未绑定函数,调用时必须显式传实例。若希望保留绑定,应使用f = d.inst这样的实例提取方式。弄清self的传递路径,可以避免大量参数错位的运行时报错。
pythonselfinstance_method修改时间:2026-08-09 01:21:27