📦 Python Containers 学习笔记 —— Set(集合)【详细版】


1. Set 是什么?

Set 是一种无序(unordered)、可变(mutable)、元素唯一(unique)的容器。

核心特性

  • 无序:不保证元素顺序,因此 不能索引、不能切片

  • 唯一:不允许重复元素(自动去重)

  • 可变:可以增删元素

  • 元素要求:set 里放的元素必须是 可哈希(hashable) 的(通常意味着“不可变”)


2. 创建 Set

2.1 直接创建(非空)


s = {1, 2, 3}

2.2 从其他可迭代对象创建(自动去重)


s = set([1, 2, 2, 3]) # {1, 2, 3} s = set((1, 2, 2, 3)) # {1, 2, 3} s = set("banana") # {'b', 'a', 'n'} (字符串按字符拆)

2.3 空集合(⚠️必考坑)


s = set() # ✅ 空 set d = {} # ⚠️ 这是空 dict,不是 set


3. Set 的“无序”意味着什么?

3.1 不能索引


s = {10, 20, 30} s[0] # ❌ TypeError

3.2 不能切片


s[1:3] # ❌ TypeError

3.3 打印顺序不固定(不要依赖输出顺序)


print({3, 1, 2}) # 可能显示 {1, 2, 3},也可能别的顺序(不要当作排序)


4. Set 的元素必须可哈希(hashable)

4.1 可放的典型元素

  • int / float / bool

  • str

  • tuple(前提:tuple 内部也都是可哈希的)

  • frozenset(不可变集合)


s = {1, "a", (1, 2)}

4.2 不能放的典型元素(⚠️重点)

  • list

  • dict

  • set


s = {[1, 2]} # ❌ TypeError: unhashable type: 'list'

4.3 tuple 也可能不行(如果内部含可变对象)


t = (1, [2, 3]) set([t]) # ❌ 因为 [2,3] 不可哈希


5. 成员判断(非常常用 & 很快)


s = {1, 2, 3} 2 in s # True 5 in s # False

📌 典型用法:快速判断“是否访问过 / 是否出现过 / 是否重复”。


6. 添加元素:addupdate

6.1 add(x):添加一个元素


s = {1, 2} s.add(3) # {1, 2, 3}

  • 添加已存在元素不会报错,也不会重复


s.add(2) # 仍然 {1,2,3}


6.2 update(iterable):批量添加(遍历加入)


s = {1, 2} s.update([2, 3, 4]) # {1, 2, 3, 4}

  • 类似 list 的 extend:把参数“摊开”逐个加入

  • ⚠️ 传字符串会按字符加入


s = set() s.update("hi") # {'h', 'i'}


7. 删除元素:remove / discard / pop / clear

7.1 remove(x):删除指定元素(不存在会报错)


s = {1, 2, 3} s.remove(2) # {1, 3} s.remove(99) # ❌ KeyError


7.2 discard(x):安全删除(不存在不报错)


s = {1, 2, 3} s.discard(2) # {1, 3} s.discard(99) # ✅ 不报错

✅ 建议:不确定元素是否存在时优先用 discard


7.3 pop():删除并返回一个元素(⚠️顺序不确定)


s = {1, 2, 3} x = s.pop() # x 是某个元素(不保证是 1/2/3 中哪个)

  • ⚠️ 不要用 pop 期待“拿到最后一个”,set 没有“最后”

  • 空 set pop 会报错


set().pop() # ❌ KeyError


7.4 clear():清空集合


s.clear() # set()


8. 集合运算(Set 的灵魂)

设:


A = {1, 2, 3} B = {3, 4}

8.1 并集 union(A 或 B)

方法:


A.union(B) # {1, 2, 3, 4}

运算符:


A | B # {1, 2, 3, 4}


8.2 交集 intersection(A 且 B)


A.intersection(B) # {3} A & B # {3}


8.3 差集 difference(在 A 不在 B)


A.difference(B) # {1, 2} A - B # {1, 2}


8.4 对称差 symmetric_difference(只在其中一个集合)


A.symmetric_difference(B) # {1, 2, 4} A ^ B # {1, 2, 4}


9. 原地更新(in-place)集合运算(会修改原集合)

9.1 运算符形式


A |= B # A = A ∪ B A &= B # A = A ∩ B A -= B # A = A - B A ^= B # A = 对称差更新

9.2 方法形式(等价)


A.update(B) A.intersection_update(B) A.difference_update(B) A.symmetric_difference_update(B)

📌 区分重点:

  • A.union(B) 不改 A(返回新集合)

  • A.update(B) 会改 A


10. 常用辅助:长度与复制

10.1 长度


len(s)

10.2 复制


t = s.copy()


11. 常见坑总结(必背)

  1. {} 是 dict,不是 set

  2. 空 set 用 set()

  3. set 无序 → 不能索引、不能切片

  4. set 元素必须可哈希(list/dict/set 不行)

  5. remove 不存在会报错;discard 不报错

  6. pop 删除哪个不确定


12. 典型应用场景(工程直觉)

  • 去重unique = set(data)

  • 快速查找/过滤if x in visited: ...

  • 集合运算:共同元素 / 差异元素 / 合并标签

  • 状态管理:已访问节点、权限集合、有效 ID 集合


13. 一句话总结(背诵版)

Set 是无序、可变、元素唯一的集合,适合去重、快速成员判断和集合运算。


如果你想把这一章做得更“考试/工程即用”,我可以再给你加两样:

  • 10 道 set 预测输出练习题(含答案)

  • set vs list vs tuple vs dict 一页终极对照表 

Appendix 

一句话定义(先记住这个)

可哈希(hashable) = 这个对象能被“稳定地”当作唯一标识来用

只要一个东西 能当 set 的元素,或 dict 的 key,它就是可哈希的。


二、直觉理解(人话版)

你可以把 hash 理解成:

给每个对象算一个“身份证号”

  • 可哈希对象:身份证号一旦算出来,永远不变

  • 不可哈希对象:身份证号可能会变 → 那就不安全

📌 Python 要求:

  • set / dict 里的元素 必须能稳定定位

  • 否则一改内容,“你是谁”就变了,Python 会乱


三、技术定义(标准版)

一个对象是 hashable,必须满足:

1️⃣ 实现了 __hash__()
2️⃣ 实现了 __eq__()
3️⃣ 对象的值在生命周期内不可变

并且有一个约定:

如果 a == b,那么 hash(a) == hash(b)


四、哪些东西是“可哈希”的?(必记)

✅ 可哈希(常见)

  • int

  • float

  • bool

  • str

  • tuple(前提:内部元素也都可哈希)

  • frozenset


hash(10) hash("abc") hash((1, 2, 3))


❌ 不可哈希(重点)

  • list

  • dict

  • set


hash([1, 2]) # ❌ TypeError hash({1: 2}) # ❌ TypeError


五、为什么 list / dict / set 不可哈希?(核心原因)

因为它们 是可变的


a = [1, 2, 3]

如果 list 能当 key:

  • 改内容前:hash = X

  • 改内容后:hash = Y

那 Python 在 set / dict 里就 找不到它原来的位置了

👉 这是灾难


六、一个经典对比例子(考试爱考)

tuple 为什么能当 key?


d = {(1, 2): "ok"}

但这个不行:


d = {([1, 2]): "no"} # ❌

📌 原因:

  • (1, 2) 不可变 → hash 稳定

  • [1, 2] 可变 → hash 不稳定


⚠️ tuple 也可能不可哈希


t = (1, [2, 3]) hash(t) # ❌

因为:

  • tuple 里 包含了不可哈希的 list

📌 规则是:

tuple 可哈希 ⇔ 内部所有元素都可哈希


七、你在 set 里遇到的所有“神秘报错”,本质都是这个


TypeError: unhashable type: 'list'

翻译成人话:

你试图把一个“会变的东西”当作唯一标识


八、给你一版「可直接放进笔记的总结」

你可以直接复制👇


可哈希(hashable)

可哈希对象是指:其值在生命周期内不可改变,并能计算出稳定的 hash 值。

  • 可哈希对象可以作为 set 的元素或 dict 的 key

  • 不可哈希对象不能用于上述用途

常见可哈希类型:

  • int, float, bool

  • str

  • tuple(内部元素也必须可哈希)

  • frozenset

不可哈希类型:

  • list

  • dict

  • set

原因:

  • 可变对象的 hash 值可能改变,无法作为稳定标识。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐