tuple和str不可变是因底层数据结构固定,修改操作会抛typeerror;其不可变性保证哈希安全与线程安全,但嵌套可变对象仍可变。

为什么 tuple 和 str 修改会报 TypeError: 'tuple' object does not support item assignment
Python 的不可变性不是靠“禁止赋值”这种表面限制实现的,而是对象在创建后,其底层数据结构不允许被原地修改。比如 tuple 在 CPython 中用固定大小的指针数组存储元素,初始化后数组地址和长度都锁死;str 同样使用只读内存块,所有“修改”操作(如 replace()、upper())都返回新对象。
常见错误现象:以为 a[0] = 1 对 tuple 或 str 是语法问题,其实它是运行时检测到类型不支持就地写入而抛出的异常。
- 不可变对象的
id()在任何“看似修改”后都不会变——因为根本没改,只是你没接住返回的新对象 - 函数参数传入
tuple或frozenset,不用担心被回调函数意外篡改,这是它能当字典键或集合元素的前提 - 注意
tuple里嵌套可变对象(如([],))仍是不可变的——外层 tuple 不能增删改,但里面 list 本身仍可.append()
__hash__ 方法怎么决定一个对象能不能进 set 或当 dict 键
不可变性本身不自动带来哈希能力,真正起作用的是对象是否实现了 __hash__ 且不为 None。CPython 默认给 tuple、str、int 等内置不可变类型实现了稳定哈希;但如果你自定义类,即使所有属性都不改,不显式定义 __hash__,它默认继承自 object,返回的是基于 id() 的值,不能用于哈希容器。
使用场景:想让自定义类实例可放入 set,必须同时满足两个条件:实例状态创建后不再变化 + 显式实现 __hash__ 并确保与 __eq__ 逻辑一致。
立即学习“Python免费学习笔记(深入)”;
专为中小型企业定制的网络办公软件,富有竞争力的十大特性: 1、独创 web服务器、数据库和应用程序全部自动傻瓜安装,建立企业信息中枢 只需3分钟。 2、客户机无需安装专用软件,使用浏览器即可实现全球办公。 3、集成Internet邮件管理组件,提供web方式的远程邮件服务。 4、集成语音会议组件,节省长途话费开支。 5、集成手机短信组件,重要信息可直接发送到员工手机。 6、集成网络硬
- 一旦定义了
__setattr__或允许修改属性,通常要设__hash__ = None,否则可能引发哈希不一致(比如 key 被修改后找不到) -
dataclass(frozen=True)会自动禁用赋值并生成__hash__,但要注意字段值本身也得是可哈希的 - 不要在
__hash__里引用可变对象或调用可能改变状态的方法,哈希值必须稳定
为什么 bytes 不可变,但 bytearray 可以?它们底层内存布局差在哪
bytes 在 CPython 中指向一块只读内存区域,所有写操作(包括切片赋值、+=)都会触发复制并新建对象;bytearray 则使用可读写缓冲区,支持原地修改,比如 b[0] = 255 直接改内存,不产生新对象。
性能影响明显:频繁修改二进制数据时用 bytearray 能避免大量临时对象和内存拷贝;但若只是解析或传输,用 bytes 更安全,也更符合函数式习惯。
-
bytes + bytes是 O(n+m) 时间,每次都要分配新内存;bytearray.extend()是均摊 O(1) -
bytes支持内存视图(memoryview(b)),但只读;bytearray的memoryview是可写的 - 网络库(如
socket.send())接受bytes,但接收缓冲区常用bytearray预分配空间再填数据
用 id() 和 is 判断不可变对象相等,为什么有时靠谱、有时翻车
小整数(-5 到 256)和短字符串在 CPython 中会被缓存复用,所以 a = 100; b = 100; a is b 返回 True;但这只是实现细节,不是语言规范。一旦超出范围(如 1000),或字符串含空格、特殊字符、动态拼接,缓存行为就不可靠。
容易踩的坑:拿 is 替代 == 比较不可变对象,尤其在测试或配置判断中,看似省事,实则把代码绑死在特定解释器行为上。
-
is比较的是对象身份(内存地址),==才是值比较——后者才反映不可变对象的语义意图 - 哪怕两个
tuple内容完全一样,只要不是同一个对象,is就是False;而==只要递归比对每个元素就足够 - 函数返回常量元组(如
return (1, 2)),不同调用可能得到不同对象,别假设它们is相等








