第 1-11 课:集合
一、本课目标
完成本课后,你将能够:
- 理解集合是什么,以及集合适合解决什么问题;
- 使用
{}或set()创建集合; - 理解集合中元素唯一、集合本身无序;
- 使用
add()、update()添加元素; - 使用
remove()、discard()、pop()和clear()删除元素; - 使用
in和not in判断元素是否存在; - 遍历集合;
- 使用交集、并集、差集和对称差集;
- 使用集合为列表去重;
- 根据实际需求在列表、元组、字典和集合之间做出选择。
二、前置知识
学习本课前,应当已经了解:
- 变量与常见数据类型;
- 条件判断;
for循环;- 字符串;
- 列表和元组;
- 字典;
in和not in。
三、集合是什么
集合(Set)是一种保存多个元素的数据结构。
它有两个非常重要的特点:
- 元素不能重复;
- 元素没有固定位置。
例如,一个 Agent 可以拥有多个工具权限:
agent_tools = {"搜索", "计算", "写作"}
如果重复写入同一个工具,集合只会保留一份:
agent_tools = {"搜索", "计算", "搜索"}
print(agent_tools)
集合中最终只有两个元素。
集合特别适合处理:
- 去除重复数据;
- 快速判断某个元素是否存在;
- 比较两组数据有哪些相同项或不同项;
- 权限、标签、课程、技能等不允许重复的数据。
四、创建集合
4.1 使用花括号创建
agent_tools = {"搜索", "计算", "写作"}
print(agent_tools)
集合使用花括号,但它与字典不同:
# 集合:里面直接保存元素
agent_tools = {"搜索", "计算"}
# 字典:里面保存“键: 值”
agent_config = {"model": "gpt-5", "enabled": True}
4.2 使用 set() 创建
agent_tools = set(["搜索", "计算", "搜索"])
print(agent_tools)
set() 会把传入的数据转换成集合,并自动去除重复元素。
4.3 创建空集合
空集合必须写成:
empty_tools = set()
不能写成:
empty_tools = {}
因为 {} 创建的是空字典,不是空集合。
可以使用 type() 验证:
print(type(set()))
print(type({}))
五、集合为什么不支持下标
列表和元组中的元素有明确位置,所以可以写:
models = ["gpt-5", "o3"]
print(models[0])
集合是无序数据结构,不保证每个元素一直处于某个固定位置,因此不能写:
agent_tools = {"搜索", "计算"}
print(agent_tools[0]) # 错误
这里的“无序”不是说 Python 每次一定用不同顺序显示,而是说:
不应该依赖集合元素的显示顺序,也不能使用下标读取集合元素。
如果业务需要稳定顺序,应使用列表或元组。
六、集合元素必须唯一
models = {"gpt-5", "o3", "gpt-5"}
print(len(models))
结果为:
2
第二个 "gpt-5" 不会产生新元素,也不会报错。
七、判断元素是否存在
集合经常配合 in 和 not in 使用:
agent_tools = {"搜索", "计算"}
print("搜索" in agent_tools)
print("写作" not in agent_tools)
正常结果:
True
True
集合非常擅长成员判断。数据较多时,通常比逐个检查列表更合适。
八、添加元素
8.1 使用 add() 添加一个元素
agent_tools = {"搜索", "计算"}
agent_tools.add("写作")
print(agent_tools)
如果添加已经存在的元素,集合不会发生变化:
agent_tools.add("搜索")
8.2 使用 update() 添加多个元素
agent_tools = {"搜索"}
agent_tools.update(["计算", "写作"])
print(agent_tools)
注意:
add()添加一个完整元素;update()从列表、元组、集合等可遍历数据中逐个取出元素并添加。
九、删除元素
9.1 remove():元素不存在时会报错
agent_tools = {"搜索", "计算"}
agent_tools.remove("搜索")
如果继续删除不存在的 "搜索",会出现 KeyError,中文意思是找不到该元素。
9.2 discard():元素不存在也不会报错
agent_tools = {"搜索", "计算"}
agent_tools.discard("写作")
当你不确定元素是否存在时,discard() 通常更安全。
9.3 pop():删除并返回一个不确定的元素
agent_tools = {"搜索", "计算"}
removed_tool = agent_tools.pop()
print(removed_tool)
集合没有固定顺序,所以不能依赖 pop() 删除某个指定元素。
如果集合为空,调用 pop() 会报错。
9.4 clear():清空集合
agent_tools = {"搜索", "计算"}
agent_tools.clear()
print(agent_tools)
结果是空集合:
set()
十、遍历集合
集合可以使用 for 循环遍历:
agent_tools = {"搜索", "计算", "写作"}
for tool in agent_tools:
print(tool)
变量名 tool 可以换成其他合法名称,但应当选择能够表达含义的名字。
不要依赖遍历顺序。如果必须按顺序输出,可以先使用 sorted() 排序:
for tool in sorted(agent_tools):
print(tool)
sorted() 会返回一个排好序的新列表,不会修改原集合。
十一、交集:两组数据共同拥有的元素
交集可以使用 & 或 intersection():
code_agent_tools = {"搜索", "计算", "代码执行"}
writer_agent_tools = {"搜索", "写作", "图片生成"}
common_tools = code_agent_tools & writer_agent_tools
print(common_tools)
结果:
{'搜索'}
也可以写成:
common_tools = code_agent_tools.intersection(writer_agent_tools)
十二、并集:合并两组数据并自动去重
并集可以使用 | 或 union():
all_tools = code_agent_tools | writer_agent_tools
print(all_tools)
结果包含两组集合的全部工具,重复的 "搜索" 只保留一份。
十三、差集:一组有、另一组没有的元素
差集使用 - 或 difference():
code_only_tools = code_agent_tools - writer_agent_tools
print(code_only_tools)
它表示代码助手拥有、写作助手没有的工具。
注意方向:
code_agent_tools - writer_agent_tools
和:
writer_agent_tools - code_agent_tools
结果通常不同。
十四、对称差集:只属于其中一组的元素
对称差集使用 ^ 或 symmetric_difference():
different_tools = code_agent_tools ^ writer_agent_tools
print(different_tools)
它会排除两组共同拥有的元素,只保留各自独有的元素。
十五、集合之间的关系判断
如果集合 A 中的所有元素都在集合 B 中,A 就是 B 的子集:
required_tools = {"搜索", "计算"}
available_tools = {"搜索", "计算", "写作"}
print(required_tools <= available_tools)
结果为 True。
也可以使用:
print(required_tools.issubset(available_tools))
print(available_tools.issuperset(required_tools))
- 子集(Subset):较小集合中的元素全部包含在较大集合中;
- 超集(Superset):较大集合包含较小集合的全部元素。
这很适合判断“当前权限是否满足所需权限”。
十六、使用集合为列表去重
model_history = ["gpt-5", "o3", "gpt-5", "o3", "gpt-5-mini"]
unique_models = set(model_history)
print(unique_models)
如果最终仍然需要列表,可以再转换:
unique_model_list = list(unique_models)
注意:这种方法不保证保留原列表顺序。
当前阶段如果既要去重又要保留顺序,可以使用:
unique_model_list = []
for model in model_history:
if model not in unique_model_list:
unique_model_list.append(model)
十七、哪些数据可以放入集合
集合元素必须是不可变且可哈希(Hashable)的数据。
当前阶段可以简单理解为:
- 字符串、数字、布尔值、元组通常可以放入集合;
- 列表、字典、普通集合不能直接放入集合。
下面会报错:
invalid_set = {[1, 2], [3, 4]}
因为列表可以被修改,不能作为集合元素。
“哈希”的内部原理将在进阶阶段逐步补充,本课只需要记住常见规则。
十八、列表、元组、字典和集合如何选择
使用列表
- 需要保留顺序;
- 允许重复;
- 需要使用下标读取或修改。
使用元组
- 需要保留顺序;
- 允许重复;
- 创建后不希望修改整体结构。
使用字典
- 需要使用“键”描述每个“值”;
- 需要通过字段名称快速读取数据。
使用集合
- 不关心顺序;
- 不允许重复;
- 经常进行成员判断、去重或集合运算。
十九、运行本课示例
进入项目根目录:
cd D:\Code\Python
运行示例:
python .\01_python基础\1_11_集合\sets.py
运行练习:
python .\01_python基础\1_11_集合\practice.py
集合的显示顺序可能与讲义不同,只要元素相同就是正常现象。
二十、常见错误
20.1 使用 {} 创建空集合
{} 是空字典,空集合必须使用 set()。
20.2 使用下标读取集合
集合不支持下标。如果需要按位置读取,应使用列表或元组。
20.3 使用 remove() 删除不存在的元素
不确定元素是否存在时,可以先用 in 判断,或者使用 discard()。
20.4 依赖集合的输出顺序
集合不保证业务上的稳定顺序。需要排序展示时使用 sorted()。
20.5 把列表或字典放入集合
列表和字典是可变数据,不能作为集合元素。
20.6 混淆 add() 和 update()
add() 添加一个元素;update() 从其他可遍历数据中添加多个元素。
二十一、课堂练习
打开:
01_python基础/1_11_集合/practice.py
本课练习将创建一个“Agent 工具权限管理器”,内容包括:
- 创建集合;
- 检查、添加和删除权限;
- 遍历权限;
- 比较两组权限的交集、并集、差集和对称差集;
- 判断所需权限是否是可用权限的子集;
- 为模型使用记录去重。
请先独立完成。遇到问题时,我会先给出定位提示,不会直接覆盖你的答案。
二十二、思考题
- 为什么
{}不能表示空集合? - 为什么不能使用
agent_tools[0]读取集合? remove()和discard()有什么区别?A - B与B - A为什么可能不同?- 使用集合为列表去重时,可能丢失什么信息?
二十三、本课小结
本课最重要的知识点:
- 集合使用
set类型表示; - 集合元素唯一,且没有可依赖的固定顺序;
- 空集合必须使用
set()创建; add()添加一个元素,update()添加多个元素;remove()删除不存在的元素会报错,discard()不会;- 集合支持交集、并集、差集和对称差集;
- 集合适合去重、成员判断和权限比较。
二十四、验收标准
完成练习后,应满足:
- 能正确创建非空集合和空集合;
- 能解释集合为什么不支持下标;
- 能使用
in判断元素; - 能正确添加、删除和遍历集合元素;
- 能计算两组集合的交集、并集、差集和对称差集;
- 能判断子集关系;
- 能使用集合完成列表去重;
- 示例和练习均可正常运行。