题目重点:区分容器槽位不可变与元素深度不可变,解释什么时候tuple能当字典key。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 讨论Python 3序列语义,CPython内存和速度差异只作实现条件,不作普遍定律。
解题路线
- list允许替换、插入、删除元素;tuple固定元素引用序列,不能重新绑定某个槽位。两者均可索引、切片与迭代,不应说tuple天然没有顺序。
- tuple内引用的对象仍可能可变。t=(items,)后items.append(1)会改变观察到的内容,tuple自身槽位没有换对象,因此不违反其不可变语义。
- tuple可哈希的前提是所有成员都可哈希;含list的tuple不能当dict key。list不可哈希是因为其内容可变,与“列表较慢”无关。
- 接口选择按语义:动态收集用list,固定记录或稳定组合键可用tuple。若记录字段多且需要名称,可用命名结构,别为了性能口号让调用方记住十几个位置。
- CPython list通常采用动态数组,索引O(1),尾追加摊还O(1),头插或中间移动O(n);tuple创建后长度固定。不保证tuple在所有任务、所有解释器上更快。
- 单元素tuple需要逗号,(x)只是括号表达式;序列拼接会新建容器,不能把不可变序列反复拼接的成本忽略。
手动走一遍
inner=[],t=(inner,);inner.append(1)后t显示([1],)。hash(t)报TypeError;(1,2)可以作为key。list转tuple只固定外层,内层list并未深冻结。
规模与取舍
索引在常见数组实现O(1),切片/转换长度k需O(k)时间空间;可变嵌套结构冻结成本按整个图计。tuple可哈希判断/计算也需访问成员,不必然O(1)。
易错点与追问
容易失分的边界
- tuple内的list不能修改。
- 所有tuple都可哈希。
- (1)误当单元素tuple。
继续深挖
- 怎样做深不可变配置?
- 可变对象定义hash会造成什么风险?
- 固定记录为什么可选dataclass?
技术参考
- Python Data Model:技术语义参考,具体题目按本文约定。
