Python集合底层用开放寻址哈希表,元素须可哈希(不可变),如list不可用;difference()比-更灵活,支持任意可迭代对象;update()批量插入优于多次add();自定义类需保证hash与eq一致。

set 的底层不是哈希表数组 + 链表,而是开放寻址法的哈希表(Python 3.11+ 进一步优化为紧凑结构),这意味着它不支持稳定遍历顺序、不能存可变对象,且 in 查找平均 O(1) 但最坏退化到 O(n)。
为什么 {[1,2]} 报 TypeError: unhashable type: 'list'
集合元素必须可哈希(即生命周期内 hash() 值不变且支持 == 比较)。list、dict、set 可变,因此不可哈希;tuple 仅当所有嵌套元素都可哈希时才可哈希。
-
hash((1, 2))✅ 正常返回整数 -
hash((1, [2]))❌ 报TypeError -
frozenset([1,2])✅ 可作集合元素:{frozenset([1,2]), frozenset([3])}
set.difference() 和 - 运算符行为一致,但参数类型限制不同
两者语义相同,但 .difference() 接受任意可迭代对象(包括生成器、字符串、字典键视图),而 - 要求右侧必须是 set 实例。
nums = {1, 2, 3}
nums.difference([2, 3, 4]) # → {1},合法
nums - [2, 3, 4] # TypeError: unsupported operand type(s)
nums - set([2, 3, 4]) # → {1},合法
实战中优先用 .difference() 避免临时转 set 开销,尤其处理大文件行、数据库游标等流式数据时。
立即学习“Python免费学习笔记(深入)”;
用 set.update() 替代多次 add() 提升批量插入性能
update() 底层一次哈希表重散列(rehash)可能触发,而多次 add() 可能触发多次,尤其在初始容量不足时。
- 差:
s = set(); [s.add(x) for x in range(1000)] - 优:
s = set(); s.update(range(1000))
注意:update() 不接受单个元素,s.update(1) 会报错 —— 因为 int 不可迭代,正确写法是 s.update([1]) 或 s.add(1)。
集合的「去重」能力依赖哈希一致性,一旦自定义类的 hash 和 eq 冲突(比如修改了影响 eq 的属性但没重算哈希),就可能让元素“消失”在集合里 —— 看得见却查不到。










