Files
PythonLearn/01_python基础/1_11_集合

第 1-11 课:集合

一、本课目标

完成本课后,你将能够:

  1. 理解集合是什么,以及集合适合解决什么问题;
  2. 使用 {}set() 创建集合;
  3. 理解集合中元素唯一、集合本身无序;
  4. 使用 add()update() 添加元素;
  5. 使用 remove()discard()pop()clear() 删除元素;
  6. 使用 innot in 判断元素是否存在;
  7. 遍历集合;
  8. 使用交集、并集、差集和对称差集;
  9. 使用集合为列表去重;
  10. 根据实际需求在列表、元组、字典和集合之间做出选择。

二、前置知识

学习本课前,应当已经了解:

  • 变量与常见数据类型;
  • 条件判断;
  • for 循环;
  • 字符串;
  • 列表和元组;
  • 字典;
  • innot in

三、集合是什么

集合Set是一种保存多个元素的数据结构。

它有两个非常重要的特点:

  1. 元素不能重复
  2. 元素没有固定位置

例如,一个 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" 不会产生新元素,也不会报错。

七、判断元素是否存在

集合经常配合 innot 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 工具权限管理器”,内容包括:

  1. 创建集合;
  2. 检查、添加和删除权限;
  3. 遍历权限;
  4. 比较两组权限的交集、并集、差集和对称差集;
  5. 判断所需权限是否是可用权限的子集;
  6. 为模型使用记录去重。

请先独立完成。遇到问题时,我会先给出定位提示,不会直接覆盖你的答案。

二十二、思考题

  1. 为什么 {} 不能表示空集合?
  2. 为什么不能使用 agent_tools[0] 读取集合?
  3. remove()discard() 有什么区别?
  4. A - BB - A 为什么可能不同?
  5. 使用集合为列表去重时,可能丢失什么信息?

二十三、本课小结

本课最重要的知识点:

  1. 集合使用 set 类型表示;
  2. 集合元素唯一,且没有可依赖的固定顺序;
  3. 空集合必须使用 set() 创建;
  4. add() 添加一个元素,update() 添加多个元素;
  5. remove() 删除不存在的元素会报错,discard() 不会;
  6. 集合支持交集、并集、差集和对称差集;
  7. 集合适合去重、成员判断和权限比较。

二十四、验收标准

完成练习后,应满足:

  • 能正确创建非空集合和空集合;
  • 能解释集合为什么不支持下标;
  • 能使用 in 判断元素;
  • 能正确添加、删除和遍历集合元素;
  • 能计算两组集合的交集、并集、差集和对称差集;
  • 能判断子集关系;
  • 能使用集合完成列表去重;
  • 示例和练习均可正常运行。