集合(set)是 Python 中专门用于存储不重复、无序元素的数据结构,基于哈希表实现。它和我们数学中“集合”的概念很相似,支持交集、并集、差集等运算。frozenset 是集合的不可变版本。
set:可变集合
创建方式
# 直接使用花括号
s = {1, 2, 3, 3, 2} # 自动去重 → {1, 2, 3}
# 使用 set() 函数(从可迭代对象构造)
s = set([1, 2, 3, 2]) # {1, 2, 3}
s = set("hello") # {'h', 'e', 'l', 'o'}
核心特性
- 无序性:元素的存储顺序由哈希值决定,与插入顺序无关(不要依赖顺序)。
- 元素唯一:自动去重,同一个值只会保留一个。
- 元素必须可哈希:只有不可变类型(如数字、字符串、元组)能放入集合,列表、字典这些可变对象不行。
常用操作
s = {1, 2, 3}
s.add(4) # 添加单个元素
s.remove(2) # 移除指定元素,不存在会报错
s.discard(5) # 安全移除,不存在也不报错
s.pop() # 随机弹出一个元素(不确定是哪个)
集合运算
a = {1, 2, 3}
b = {2, 3, 4}
a & b # 交集 → {2, 3} 也可以用 a.intersection(b)
a | b # 并集 → {1, 2, 3, 4} a.union(b)
a - b # 差集(在a不在b)→ {1} a.difference(b)
a ^ b # 对称差集(只出现在一边)→ {1, 4} a.symmetric_difference(b)
实际使用场景
- 快速去重:对一个大列表去重,
list(set(my_list))比手写循环快得多。 - 成员判断:对大量数据的“是否存在”检查,集合的 O(1) 查找远快于列表的 O(n)。
- 关系判断:检查一个列表是否包含另一个列表的所有元素时,转成集合做差集或子集判断。
- 数学集合运算:如统计两个用户组的共同用户、差异用户。
frozenset:不可变集合
frozenset 与 set 行为几乎一样,只是创建后不可修改(不能 add、remove 等),因此它是可哈希的,可以作为字典的键,也可以放入另一个 set 中。
创建
fs = frozenset([1, 2, 3]) # frozenset({1, 2, 3})
为什么需要 frozenset
- 当你需要一个“常量集合”,不希望被意外修改时。
- 当你想用集合作为字典的键时(set 本身不可哈希,不能当键),比如:
groups = {frozenset({'Alice', 'Bob'}): 'team_a'}
- 实际上,在装饰器、缓存等场景中,frozenset 的不可变性使其更安全。
与 set 的简单对比
| 特性 | set | frozenset |
|------|-----|-----------|
| 可变性 | 可变,可增删 | 不可变,一旦创建不能修改 |
| 可哈希 | 否(不能作为字典键) | 是(可以作为字典键) |
| 适用场景 | 普通集合操作 | 常量化集合、嵌套或当键 |
注意事项
- 集合虽然本身是无序的,但 Python 3.7 以上保留插入顺序?不,字典才保留插入顺序,集合没有这个保证,不要依赖顺序。
- 创建空集合只能用
set(),不能用{}(因为{}是空字典)。 - 集合操作多数有对应的运算符版本(
|,&,-,^),也有等价的方法名(union,intersection等),方法可以接受任意可迭代对象,运算符两边则必须是集合。
集合和 frozenset 是处理“唯一性”需求最直接有力的工具,尤其在数据去重、快速查找和关系运算中,远比列表高效和语义清晰。