>>>PyPathPython 学习站
首页›基础篇›kp-003
基础篇 · Foundations lv.1 入门 kp-003

变量与引用(名字绑定)

前置知识:kp-002

1. 一句话定义

Python 的变量不是"装值的盒子",而是指向对象的标签——赋值语句做的是"名字 → 对象"的绑定,而不是把值复制进去。

2. 为什么重要

这是 Python 第一块真正的"心智地基":它解释了赋值、参数传递、可变默认值、深浅拷贝等一大串行为的根源。理解错了,之后每个模块都会摔跤。

3. 前置知识

kp-001、kp-002。

4. 核心概念

  • 对象(object):内存中的一块数据,自带类型和身份(id() 返回的地址感标识)。
  • 名字(name):指向对象的标签,存放在命名空间里。
  • 赋值:x = 10 的含义是"把名字 x 绑定到整数对象 10",10 本身不变。
  • 多个名字可指向同一对象:y = x 只复制了"标签",不复制对象。

5. 原理与机制

python
a = [1, 2]
b = a              # b 与 a 指向同一个列表对象
b.append(3)
print(a)           # [1, 2, 3]  ← a 也"变"了,其实是同一个对象

x = 10
y = x
y = 20             # 给 y 重新绑定到新对象 20,x 不受影响
print(x)           # 10

规则:修改对象(b.append)对所有引用可见;重新绑定名字(y = 20)只影响这个名字。id()、is 运算符可验证身份(详见 kp-005、kp-028)。

6. 关键事实(模型/图示)

text
赋值前:      a ──┐
                  ├──► [1, 2]        (同一个对象)
b = a 后:    b ──┘

y = 20 后:   y ──► 20        (新对象)
              x ──► 10        (旧对象,未动)

  • 类型跟着对象走:名字本身没有类型,所以同一名字可先后绑定不同类型——这就是"动态类型"。
  • 小整数(-5~256)等常见对象会被 CPython 缓存复用,属实现细节,不要依赖。

7. 直观类比

变量是便利贴,不是抽屉。同一件行李(对象)可以贴多张便利贴(多个名字);撕下一张贴到新行李上(重新绑定),不影响旧行李和其他便利贴。而"修改行李内容"(append),所有贴着它的人都看得见。

8. 实例与案例

函数参数传递就是名字绑定的重演(详见 kp-007 的"传引用/传值之争"小节):

python
def mutate(lst):
    lst.append(99)      # 修改对象 → 调用方看得见

def rebind(lst):
    lst = [0]           # 重新绑定局部名字 → 调用方看不见

9. 常见误区

  1. "Python 传值/传引用"二选一的说法都不准确 —— 准确说法是"传对象引用的共享"(call by object reference)。
  2. 以为 b = a 复制了列表 —— 只复制引用,复制列表要用 a.copy() 或 list(a)(深浅拷贝见 kp-028)。
  3. 以为变量有类型 —— 对象才有类型;type(x) 查的是 x 当前绑定的对象。

10. 自测题

  1. x = [1]; y = x; y = [2] 后,x 是什么?为什么?
  2. 如何验证两个名字指向同一个对象?
  3. 为什么 def f(lst=[]): lst.append(1) 是著名陷阱?(预告 kp-007)
参考答案
  1. [1]。y = [2] 是把 y 重新绑定到新对象,未修改原列表。
  2. x is y(身份比较)或比较 id(x) == id(y)。
  3. 默认值在函数定义时求值一次并绑定到该参数——所有不带该参数的调用共享同一个列表对象。

11. 与其他知识点的关系

  • kp-004 数据类型总览:哪些类型可变是分水岭。
  • kp-028 深浅拷贝:想复制对象时必读。
  • kp-033 内存与 GC:对象何时被回收。

12. 延伸阅读

  • Fluent Python 第 6 章 "Variables Are Not Boxes"
  • Python 官方教程 3.1 节