Python 中变量赋值的本质:引用传递 ≠ 引用绑定的同步更新

11次阅读

Python 中变量赋值的本质:引用传递 ≠ 引用绑定的同步更新

python 中所有变量都存储对象引用,但赋值操作(如 `a = b`)只是复制引用值,而非建立引用间的动态关联;修改变量本身(如 `b = b.next`)不会影响其他已保存该引用的变量。

在链表合并等指针操作中,理解 python 变量赋值的“快照式引用复制”机制至关重要。以 leetcode 经典题 mergeTwoLists 为例:

curr.next = list1   # ✅ 将 list1 当前指向的 Listnode 对象的引用,赋给 curr.next list1 = list1.next  # ✅ 仅改变 list1 变量自身所持有的引用,指向下一个节点

这两行代码看似连续,实则完全独立:第一行是一次性的引用拷贝——curr.next 获得了 list1 此刻所指对象的内存地址;第二行则是重新绑定 list1 这个变量名,让它指向另一个对象。这与 C/c++ 中的指针“别名”或“间接寻址”有本质区别:Python 中没有真正的“指针变量”,只有绑定到对象的名称(name)

你提供的列表示例很好地印证了这一原理:

a = [] b = [1] a = b          # a 和 b 现在绑定到同一个 list 对象 b.append(2)    # 修改该对象的内容 → a 也能看到变化(因 a、b 指向同一可变对象) print(a)       # [1, 2] print(id(a) == id(b))  # True —— 内存地址相同

⚠️ 关键区分点在此:

立即学习Python免费学习笔记(深入)”;

  • b.append(2) 是对对象内容的就地修改(in-place mutation) → 所有引用该对象的变量均可见;
  • 而 list1 = list1.next 是对变量绑定关系的重置(rebinding) → 仅改变 list1 这个名字的指向,不影响 curr.next 已保存的旧引用。

✅ 正确类比:
把 list1 想象成一张写着“房间号 301”的便签;curr.next = list1 相当于抄下“301”贴在 curr.next 上;list1 = list1.next 则是把原便签擦掉,重写为“302”。curr.next 上的“301”不会自动变成“302”。

? 总结:

  • Python 中赋值永远是引用拷贝(shallow copy of reference),不是引用绑定的“联动”;
  • 要让多个变量反映同一对象的状态变化,必须通过修改对象自身属性(如 node.val = …, lst.append()),而非重赋值变量;
  • 在链表/树等数据结构操作中,curr = curr.next 或 p = p.left 都是安全的变量重绑定,不会破坏已构建的结构连接——这正是该算法能正确拼接链表的底层保障。

text=ZqhQzanResources