【Python入门】6.5数据容器--集合(set)
Python 集合(Set)系统学习指南
集合(Set)是 Python 中无序、不重复、元素可哈希的核心数据结构,核心价值在于快速去重、元素存在性判断、集合运算(交集/并集/差集),底层基于哈希表实现,查找效率极高(时间复杂度 O(1))。本文将从基础到进阶,全面覆盖集合的知识点。
一、集合的核心特性
在学习具体操作前,先明确集合的 3 个关键特性(决定了它的使用场景):
- 无序性:集合中的元素没有固定顺序,每次打印结果可能不同(Python 3.7+ 对字典有序优化,但集合仍无序)。
- 不重复性:集合会自动过滤重复元素,这是去重的核心用法。
- 元素可哈希:集合中的元素必须是不可变类型(如整数、字符串、元组、布尔值),不可变类型(列表、字典、集合)不能作为集合元素(会报
TypeError)。
哈希(Hash):将任意长度的数据转换为固定长度的唯一标识,不可变类型的哈希值固定,可变类型的哈希值会随内容变化,因此无法作为集合/字典的键。
二、集合的创建
Python 中创建集合有 2 种常用方式:{} 直接创建、set() 函数转换,注意空集合的创建细节。
1. 直接创建({})
语法:集合名 = {元素1, 元素2, ..., 元素n}
# 正常创建(自动去重)
s1 = {1, 2, 3, 2, "a"}
print(s1) # 输出:{1, 2, 'a'}(顺序不确定)
# 重复元素被自动过滤
s2 = {1, 1, 2, 2}
print(s2) # 输出:{1, 2}
# 元素必须可哈希(以下代码报错)
# s3 = {1, [2, 3]} # TypeError: unhashable type: 'list'
# s4 = {1, {"name": "Tom"}} # TypeError: unhashable type: 'dict'
2. set() 函数创建(转换型)
set() 可将可迭代对象(列表、元组、字符串、range 等)转换为集合,同样自动去重。
语法:集合名 = set(可迭代对象)
# 列表转集合(去重)
list1 = [1, 2, 2, 3]
s3 = set(list1)
print(s3) # 输出:{1, 2, 3}
# 字符串转集合(按字符拆分,去重)
s4 = set("abac")
print(s4) # 输出:{'a', 'b', 'c'}(顺序不确定)
# 元组转集合
tuple1 = (1, 2, 3, 3)
s5 = set(tuple1)
print(s5) # 输出:{1, 2, 3}
# range 转集合
s6 = set(range(5))
print(s6) # 输出:{0, 1, 2, 3, 4}
3. 空集合的创建
⚠️ 注意:{} 创建的是空字典,不是空集合!空集合必须用 set() 创建:
# 错误:创建的是空字典
empty_dict = {}
print(type(empty_dict)) # 输出:<class 'dict'>
# 正确:创建空集合
empty_set = set()
print(type(empty_set)) # 输出:<class 'set'>
print(empty_set) # 输出:set()
三、集合的核心操作
集合的操作主要分为 5 类:添加元素、删除元素、查找元素、集合运算、其他常用操作,以下逐一详解。
(一)添加元素
集合提供 2 种添加方法:add()(添加单个元素)、update()(添加多个元素,接收可迭代对象)。
1. add():添加单个元素
语法:集合名.add(元素)
- 若元素已存在,不报错也不重复添加;
- 元素必须可哈希(不可变类型)。
s = {1, 2, 3}
s.add(4) # 添加不存在的元素
print(s) # 输出:{1, 2, 3, 4}
s.add(2) # 添加已存在的元素(无效果)
print(s) # 输出:{1, 2, 3, 4}
s.add(("a", "b")) # 添加元组(可哈希)
print(s) # 输出:{1, 2, 3, 4, ('a', 'b')}
2. update():添加多个元素
语法:集合名.update(可迭代对象)
- 接收列表、元组、字符串、集合等可迭代对象,将其元素逐个添加到集合中;
- 自动去重。
s = {1, 2, 3}
s.update([3, 4, 5]) # 添加列表(去重)
print(s) # 输出:{1, 2, 3, 4, 5}
s.update((5, 6), "ab") # 同时添加元组和字符串
print(s) # 输出:{1, 2, 3, 4, 5, 6, 'a', 'b'}
s.update({7, 8}) # 添加集合
print(s) # 输出:{1, 2, 3, 4, 5, 6, 7, 8, 'a', 'b'}
(二)删除元素
集合提供 4 种删除方法:remove()、discard()、pop()、clear(),核心区别在于“元素不存在时是否报错”和“删除逻辑”。
| 方法 | 功能描述 | 元素不存在时的行为 |
|---|---|---|
remove(x) | 删除集合中的指定元素 x | 报错 KeyError |
discard(x) | 删除集合中的指定元素 x | 不报错(无效果) |
pop() | 随机删除并返回集合中的一个元素(无序特性) | 集合为空时报错 KeyError |
clear() | 清空集合(保留集合对象,元素为空) | 无报错(空集合调用也安全) |
s = {1, 2, 3, 4, 5}
# 1. remove(x):元素不存在报错
s.remove(3)
print(s) # 输出:{1, 2, 4, 5}
# s.remove(10) # KeyError: 10(元素不存在)
# 2. discard(x):元素不存在无效果
s.discard(4)
print(s) # 输出:{1, 2, 5}
s.discard(10) # 无报错,集合不变
print(s) # 输出:{1, 2, 5}
# 3. pop():随机删除(无序)
deleted = s.pop()
print("删除的元素:", deleted) # 输出不确定(如 1)
print(s) # 输出:{2, 5}(剩余元素)
# 4. clear():清空集合
s.clear()
print(s) # 输出:set()
# 空集合调用 pop() 报错
# empty_set = set()
# empty_set.pop() # KeyError: 'pop from an empty set'
(三)查找元素
集合没有索引(无序特性),因此无法通过 [索引] 访问元素,只能判断元素是否存在(核心用法)。
语法:元素 in 集合(存在返回 True,不存在返回 False)
s = {1, 2, 3, "a"}
print(2 in s) # 输出:True
print("b" in s) # 输出:False
print(5 not in s) # 输出:True(not in 表示不存在)
为什么集合的
in判断比列表快?
列表是线性结构,查找元素需遍历所有元素(时间复杂度 O(n));集合是哈希表结构,通过元素的哈希值直接定位(时间复杂度 O(1)),数据量越大,效率差异越明显。
(四)集合运算(核心功能)
集合最强大的功能是集合运算(交集、并集、差集、对称差集),适用于数据筛选、去重、对比等场景,支持运算符和方法两种调用方式(推荐运算符,更简洁)。
假设有两个集合:
a = {1, 2, 3, 4} # 集合 A
b = {3, 4, 5, 6} # 集合 B
1. 交集(& / intersection())
- 含义:两个集合中共同存在的元素。
- 语法:
a & b或a.intersection(b)
print(a & b) # 输出:{3, 4}
print(a.intersection(b)) # 输出:{3, 4}
2. 并集(| / union())
- 含义:两个集合中所有元素(自动去重)。
- 语法:
a | b或a.union(b)
print(a | b) # 输出:{1, 2, 3, 4, 5, 6}
print(a.union(b)) # 输出:{1, 2, 3, 4, 5, 6}
3. 差集(- / difference())
- 含义:集合 A 中存在但集合 B 中不存在的元素(顺序影响结果)。
- 语法:
a - b(A 减 B)或a.difference(b)
print(a - b) # 输出:{1, 2}(A 有,B 没有)
print(b - a) # 输出:{5, 6}(B 有,A 没有)
print(a.difference(b)) # 输出:{1, 2}
4. 对称差集(^ / symmetric_difference())
- 含义:两个集合中互不相同的元素(并集 - 交集)。
- 语法:
a ^ b或a.symmetric_difference(b)
print(a ^ b) # 输出:{1, 2, 5, 6}
print(a.symmetric_difference(b)) # 输出:{1, 2, 5, 6}
5. 集合关系判断(子集/超集/互斥)
| 关系 | 运算符 | 方法 | 含义 |
|---|---|---|---|
| 子集 | a <= b | a.issubset(b) | A 中所有元素都在 B 中(A 是 B 的子集) |
| 真子集 | a < b | - | A 是 B 的子集,且 A ≠ B |
| 超集 | a >= b | a.issuperset(b) | B 中所有元素都在 A 中(A 是 B 的超集) |
| 真超集 | a > b | - | A 是 B 的超集,且 A ≠ B |
| 互斥(无交集) | - | a.isdisjoint(b) | A 和 B 没有共同元素(交集为空) |
a = {1, 2, 3}
b = {1, 2, 3, 4, 5}
c = {6, 7}
# 子集判断
print(a <= b) # 输出:True(a 所有元素都在 b 中)
print(a.issubset(b)) # 输出:True
print(a < b) # 输出:True(a 是 b 的真子集)
# 超集判断
print(b >= a) # 输出:True(b 包含 a 所有元素)
print(b.issuperset(a)) # 输出:True
# 互斥判断
print(a.isdisjoint(c)) # 输出:True(a 和 c 无交集)
print(a.isdisjoint(b)) # 输出:False(a 和 b 有交集)
(五)其他常用操作
1. 集合复制(copy())
创建集合的浅拷贝(新集合,修改新集合不影响原集合):
s = {1, 2, 3}
s_copy = s.copy()
s_copy.add(4)
print(s) # 输出:{1, 2, 3}(原集合不变)
print(s_copy) # 输出:{1, 2, 3, 4}(新集合变化)
2. 集合长度(len())
获取集合中元素的个数:
s = {1, 2, 3, "a"}
print(len(s)) # 输出:4
3. 遍历集合(for 循环)
因集合无序,遍历顺序与添加顺序无关:
s = {1, 2, 3, "a"}
for elem in s:
print(elem) # 输出顺序不确定(如:1, 'a', 2, 3)
四、集合推导式(快速创建集合)
集合推导式是 Python 中简洁创建集合的方式,语法与列表推导式类似,但用 {} 包裹,自动去重。
语法:{表达式 for 变量 in 可迭代对象 if 条件}
- 作用:遍历可迭代对象,根据条件筛选元素,通过表达式转换后生成集合(自动去重)。
示例:
# 1. 生成 1-10 的偶数集合
even_set = {x for x in range(1, 11) if x % 2 == 0}
print(even_set) # 输出:{2, 4, 6, 8, 10}
# 2. 字符串去重并转换为大写
str_set = {c.upper() for c in "abac"}
print(str_set) # 输出:{'A', 'B', 'C'}
# 3. 列表去重并筛选大于 3 的元素
list1 = [1, 2, 2, 3, 4, 5, 5]
filter_set = {x for x in list1 if x > 3}
print(filter_set) # 输出:{4, 5}
五、不可变集合(frozenset)
Python 中还有一种不可变集合(frozenset),与普通集合(set)的区别是:
frozenset不可修改(不能添加、删除元素);frozenset可哈希,因此可以作为普通集合的元素或字典的键。
1. 创建 frozenset
语法:frozenset(可迭代对象)
# 创建不可变集合
fs = frozenset({1, 2, 3})
print(fs) # 输出:frozenset({1, 2, 3})
print(type(fs)) # 输出:<class 'frozenset'>
# 不可修改(以下代码报错)
# fs.add(4) # AttributeError: 'frozenset' object has no attribute 'add'
# fs.remove(2) # AttributeError: 'frozenset' object has no attribute 'remove'
2. frozenset 的用途(作为集合元素/字典键)
# 1. frozenset 作为普通集合的元素
s = {frozenset({1, 2}), frozenset({3, 4})}
print(s) # 输出:{frozenset({1, 2}), frozenset({3, 4})}
# 2. frozenset 作为字典的键
d = {frozenset({1, 2}): "a", frozenset({3, 4}): "b"}
print(d) # 输出:{frozenset({1, 2}): 'a', frozenset({3, 4}): 'b'}
六、集合的应用场景
结合集合的特性,以下是最常用的实际场景:
1. 快速去重
这是集合最经典的用法,比列表推导式去重更简洁高效:
# 列表去重(转换为集合再转回列表)
list1 = [1, 2, 2, 3, 3, 3]
unique_list = list(set(list1))
print(unique_list) # 输出:[1, 2, 3](顺序不确定,若需保留顺序可结合字典)
# 保留原列表顺序的去重(Python 3.7+ 字典有序)
unique_list_ordered = list(dict.fromkeys(list1))
print(unique_list_ordered) # 输出:[1, 2, 3]
2. 元素存在性判断(高效)
适合需要频繁判断“元素是否存在”的场景(如用户权限校验、数据查重):
# 模拟用户权限集合
user_permissions = {"read", "write", "delete"}
# 判断是否有管理员权限
if "admin" in user_permissions:
print("有管理员权限")
else:
print("无管理员权限") # 输出:无管理员权限
3. 数据筛选(交集/并集/差集)
适用于两个数据集的对比分析(如筛选共同用户、合并数据、找出差异数据):
# 示例:筛选两个班级的共同学生
class1 = {"Tom", "Jerry", "Alice"}
class2 = {"Alice", "Bob", "Charlie"}
# 共同学生(交集)
common_students = class1 & class2
print("共同学生:", common_students) # 输出:{'Alice'}
# 所有学生(并集)
all_students = class1 | class2
print("所有学生:", all_students) # 输出:{'Tom', 'Jerry', 'Alice', 'Bob', 'Charlie'}
# 仅 class1 有的学生(差集)
only_class1 = class1 - class2
print("仅 class1 有:", only_class1) # 输出:{'Tom', 'Jerry'}
4. 快速统计不重复元素个数
结合 len() 和 set(),统计可迭代对象中不重复元素的数量:
# 统计字符串中不重复字符的个数
s = "abacabc"
unique_char_count = len(set(s))
print("不重复字符个数:", unique_char_count) # 输出:3(a、b、c)
七、注意事项与常见坑
- 无序性导致的索引问题:集合没有索引,不能用
s[0]访问元素,也不能切片(如s[1:3]),只能用in判断或遍历。 - 元素必须可哈希:列表、字典、集合不能作为集合元素,若需存储多个值,可改用元组(如
(1, 2))。 {}与set()的区别:{}不能创建空集合(创建的是空字典),空集合必须用set()。- 集合运算的对象必须是集合:运算符(
&、|等)两边必须是集合,若需对列表/元组运算,需先转换为集合:list1 = [1, 2, 3] list2 = [3, 4, 5] # 错误:列表不能直接用 & 运算 # print(list1 & list2) # TypeError # 正确:先转集合再运算 print(set(list1) & set(list2)) # 输出:{3} frozenset的不可修改性:若需频繁添加/删除元素,用普通set;若需作为集合元素或字典键,用frozenset。
八、总结
集合是 Python 中高效的“去重+集合运算”工具,核心要点:
- 特性:无序、不重复、元素可哈希;
- 核心操作:添加(
add()/update())、删除(remove()/discard()/pop()/clear())、查找(in)、集合运算(&/|/-/^); - 推导式:
{表达式 for 变量 in 可迭代对象 if 条件}(快速创建集合); - 不可变集合:
frozenset(不可修改,可作为集合元素/字典键); - 应用场景:去重、元素存在性判断、数据筛选、统计不重复元素个数。
建议多结合实际场景练习(如学生信息管理、数据对比),熟练掌握集合的核心用法,提升代码效率。
更多推荐


所有评论(0)