Python 中对象“可变 / 不可变”到底是指什么?

8次阅读

python对象的“可变/不可变”指其内存值能否原地修改:不可变对象(如int、str、tuple)任何修改操作都生成新对象,id()改变;可变对象(如list、dict、set)调用append()等方法后内容变但id()不变。

Python 中对象“可变 / 不可变”到底是指什么?

Python 中对象的“可变 / 不可变”指的是该对象在创建后,其**内存中存储的值能否被原地修改**。不是指变量能不能重新赋值,而是看对象自身的内容是否允许被改变而不新建对象。

关键区别:id() 是否变化

判断一个对象是否可变,最直接的方式是观察对它做“修改操作”后,id()(即内存地址)是否改变:

  • 不可变对象(如 intstrtuple):任何看似“修改”的操作(比如 s += "x"i += 1)都会创建新对象,原对象不变,id() 一定不同;
  • 可变对象(如 listdictset):调用 .append().update().add() 等方法后,内容变了,但 id() 保持不变——它是同一个对象,只是内部状态被更新了。

常见误区:变量名 ≠ 对象

很多人混淆“给变量重新赋值”和“修改对象本身”。例如:

a = [1, 2] a = [3, 4]  # 这不是修改列表,而是让 a 指向一个新列表

这跟可变性无关——无论对象可不可变,变量都能重新绑定。真正体现可变性的操作是:不改变变量名绑定关系,却改变了它所指对象的内容。比如:

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

lst = [1, 2] lst.append(3)  # lst 仍指向原对象,但内容变成 [1, 2, 3],id(lst) 不变

为什么设计成这样?影响在哪?

不可变性带来安全性与一致性:

  • strtuple 可作字典键或集合元素,因为它们哈希值稳定;
  • 函数默认参数若用可变对象(如 def f(x=[])),多次调用会共享同一列表,导致意外累积——这是典型因忽略可变性引发的 bug
  • 传参时,可变对象在函数内被修改,会影响外部原始对象(所谓“传对象引用”,效果类似传指针);不可变对象则不会,因为任何“修改”都生成新对象。

如何快速查某个类型是否可变?

没有绝对的“查文档才知”,但有实用经验:

  • 内置原子类型基本都不可变:intFloatboolstrbytesNoneTypetuple(注意:tuple 内部可以含可变对象,但 tuple 本身结构不可变);
  • 容器类若提供原地修改方法(.append().clear().pop() 等),大概率可变:listdictsetbytearray
  • 自定义类默认可变(除非手动冻结,如用 @dataclass(frozen=True) 或限制 __slots__ 并禁写逻辑)。

text=ZqhQzanResources