feat(python基础): 完成第十一至十三课教学内容

This commit is contained in:
zhiye.sun
2026-08-03 14:22:36 +08:00
parent b5023b8e25
commit 298e5b46ea
11 changed files with 1862 additions and 29 deletions

View File

@@ -0,0 +1,530 @@
# 第 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` 判断元素;
- 能正确添加、删除和遍历集合元素;
- 能计算两组集合的交集、并集、差集和对称差集;
- 能判断子集关系;
- 能使用集合完成列表去重;
- 示例和练习均可正常运行。

View File

@@ -0,0 +1,104 @@
# 第 1-11 课课堂练习Agent 工具权限管理器
#
# 完成要求:
# 1. 根据注释完成集合的创建、成员判断、添加、删除、遍历和集合运算。
# 2. 使用有意义的英文蛇形变量名。
# 3. 不要依赖集合的显示顺序。
# 4. 删除可能不存在的元素时使用 discard(),或先使用 in 判断。
# 5. 不要删除题目注释。
# 6. 完成后运行本文件并核对预期结果。
# 练习一:创建集合 agent_tools包含以下工具
# "搜索"、"计算"、"写作"、"搜索"。
# 输出集合和元素数量,观察重复的“搜索”是否只保留一份。
# 练习二:创建空集合 disabled_tools。
# 输出它的值和类型,确认类型是 set而不是 dict。
# 练习三:完成成员判断:
# 1. 判断 agent_tools 中是否存在“搜索”,保存到 can_search
# 2. 判断 agent_tools 中是否不存在“图片生成”,保存到 cannot_generate_image
# 3. 输出两个判断结果。
# 练习四:使用 add() 向 agent_tools 添加“代码执行”。
# 再次使用 add() 添加已经存在的“搜索”。
# 输出添加后的集合和元素数量,确认没有产生重复元素。
# 练习五:使用 update() 一次添加“图片生成”和“网页浏览”。
# 传给 update() 的数据可以使用列表。
# 输出更新后的集合。
# 练习六:完成安全删除:
# 1. 使用 remove() 删除确定存在的“网页浏览”;
# 2. 使用 discard() 删除不存在的“语音识别”;
# 3. 输出删除后的集合,确认程序没有报错。
# 练习七:使用 for 遍历 agent_tools。
# 为了让输出顺序稳定,请遍历 sorted(agent_tools)。
# 每行按照“可用工具:搜索”的格式输出。
# 练习八:创建两个集合:
# code_agent_tools = {"搜索", "计算", "代码执行"}
# writer_agent_tools = {"搜索", "写作", "图片生成"}
# 计算并输出:
# 1. 交集 common_tools
# 2. 并集 all_tools
# 3. 代码助手独有的差集 code_only_tools
# 4. 对称差集 different_tools。
# 练习九:创建以下两个集合:
# required_tools = {"搜索", "计算"}
# available_tools = {"搜索", "计算", "写作"}
# 使用 <= 判断 required_tools 是否是 available_tools 的子集,
# 将结果保存到 has_required_tools 并输出。
# 练习十:为模型使用记录去重:
# model_history = ["gpt-5", "o3", "gpt-5", "o3", "gpt-5-mini"]
# 将列表转换成集合 unique_models 并输出;
# 再把集合转换成列表 unique_model_list 并输出。
# 注意:转换后的顺序可能与原列表不同。
# 练习十一:创建集合 current_permissions
# {"读取配置", "修改配置", "执行任务"}
# 再创建集合 revoked_permissions
# {"修改配置", "删除配置"}
# 使用差集得到 remaining_permissions
# 表示撤销相关权限后仍然保留的权限,并输出结果。
# 预期核心结果:
# agent_tools 中重复的“搜索”只保留一份;
# disabled_tools 的类型是 set
# can_search = True
# cannot_generate_image = True
# 重复执行 add("搜索") 不会增加元素数量;
# discard() 删除不存在的元素时不会报错;
# common_tools = {"搜索"}
# all_tools 包含两组 Agent 的全部工具;
# code_only_tools = {"计算", "代码执行"}
# different_tools 不包含共同拥有的“搜索”;
# has_required_tools = True
# unique_models 只有三个元素;
# remaining_permissions = {"读取配置", "执行任务"}。
# 完成后进行自查:
# 1. 空集合是否使用 set() 创建;
# 2. 是否理解集合会自动去除重复元素;
# 3. add() 和 update() 是否按要求分别使用;
# 4. 删除不存在的元素时是否避免了 KeyError
# 5. 遍历时是否没有依赖集合自身的顺序;
# 6. 是否能区分交集、并集、差集和对称差集;
# 7. 是否理解差集运算的左右方向;
# 8. 是否能使用子集判断检查权限;
# 9. 是否理解集合去重可能打乱原列表顺序。

View File

@@ -0,0 +1,116 @@
# 第 1-11 课示例:集合
#
# 本文件集中演示集合的创建、成员判断、增删、遍历和集合运算。
# 集合没有可依赖的固定顺序,因此你看到的元素显示顺序可能不同。
print("一、创建集合")
# 集合使用花括号保存多个不重复的元素。
agent_tools = {"搜索", "计算", "写作"}
print(f"Agent 工具:{agent_tools}")
print(f"工具数量:{len(agent_tools)}")
# 重复元素只会保留一份。
models = {"gpt-5", "o3", "gpt-5"}
print(f"自动去重后的模型:{models}")
# 空集合必须使用 set(),因为 {} 表示空字典。
empty_tools = set()
print(f"空集合:{empty_tools}")
print(f"空集合类型:{type(empty_tools)}")
print(f"空字典类型:{type({})}")
print("\n二、成员判断")
print(f"是否拥有搜索工具:{'搜索' in agent_tools}")
print(f"是否没有图片生成工具:{'图片生成' not in agent_tools}")
print("\n三、添加元素")
# add() 每次添加一个元素。
agent_tools.add("代码执行")
print(f"添加一个工具后:{agent_tools}")
# 重复添加不会报错,也不会产生重复元素。
agent_tools.add("搜索")
print(f"重复添加搜索后:{agent_tools}")
# update() 可以从列表等可遍历数据中添加多个元素。
agent_tools.update(["图片生成", "网页浏览"])
print(f"添加多个工具后:{agent_tools}")
print("\n四、删除元素")
# remove() 用于删除确定存在的元素。
agent_tools.remove("网页浏览")
print(f"remove() 删除后:{agent_tools}")
# discard() 在元素不存在时也不会报错。
agent_tools.discard("不存在的工具")
print(f"discard() 安全删除后:{agent_tools}")
# pop() 会删除并返回一个不确定的元素。
# 因为集合无序,不应猜测它会删除哪一个。
temporary_tools = {"工具甲", "工具乙"}
removed_tool = temporary_tools.pop()
print(f"pop() 删除的元素:{removed_tool}")
print(f"pop() 删除后的集合:{temporary_tools}")
print("\n五、遍历集合")
# sorted() 会返回排好序的新列表,方便得到稳定的展示结果。
for tool in sorted(agent_tools):
print(f"可用工具:{tool}")
print("\n六、集合运算")
code_agent_tools = {"搜索", "计算", "代码执行"}
writer_agent_tools = {"搜索", "写作", "图片生成"}
# 交集:两组集合共同拥有的元素。
common_tools = code_agent_tools & writer_agent_tools
print(f"共同工具:{common_tools}")
# 并集:两组集合的全部元素,重复项只保留一份。
all_tools = code_agent_tools | writer_agent_tools
print(f"全部工具:{all_tools}")
# 差集:左侧集合有、右侧集合没有的元素。
code_only_tools = code_agent_tools - writer_agent_tools
writer_only_tools = writer_agent_tools - code_agent_tools
print(f"代码助手独有工具:{code_only_tools}")
print(f"写作助手独有工具:{writer_only_tools}")
# 对称差集:只属于其中一组、不属于两组公共部分的元素。
different_tools = code_agent_tools ^ writer_agent_tools
print(f"两组不同的工具:{different_tools}")
print("\n七、子集与超集")
required_tools = {"搜索", "计算"}
available_tools = {"搜索", "计算", "写作"}
has_required_tools = required_tools <= available_tools
print(f"现有权限是否满足要求:{has_required_tools}")
print(f"required_tools 是否为子集:{required_tools.issubset(available_tools)}")
print(f"available_tools 是否为超集:{available_tools.issuperset(required_tools)}")
print("\n八、使用集合去重")
model_history = ["gpt-5", "o3", "gpt-5", "o3", "gpt-5-mini"]
unique_models = set(model_history)
print(f"原始模型记录:{model_history}")
print(f"去重后的模型集合:{unique_models}")
# 如果后续操作必须使用列表,可以通过 list() 转换回来。
# 转换后的列表不保证保留原列表的先后顺序。
unique_model_list = list(unique_models)
print(f"转换后的模型列表:{unique_model_list}")