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