From 298e5b46ea5a5a6eabbb5d4c2cc9a7e9b8b8cd8a Mon Sep 17 00:00:00 2001 From: "zhiye.sun" Date: Mon, 3 Aug 2026 14:22:36 +0800 Subject: [PATCH] =?UTF-8?q?feat(python=E5=9F=BA=E7=A1=80):=20=E5=AE=8C?= =?UTF-8?q?=E6=88=90=E7=AC=AC=E5=8D=81=E4=B8=80=E8=87=B3=E5=8D=81=E4=B8=89?= =?UTF-8?q?=E8=AF=BE=E6=95=99=E5=AD=A6=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 01_python基础/1_11_集合/README.md | 530 ++++++++++++++++++ 01_python基础/1_11_集合/practice.py | 104 ++++ 01_python基础/1_11_集合/sets.py | 116 ++++ 01_python基础/1_12_函数/README.md | 300 ++++++++++ 01_python基础/1_12_函数/functions.py | 56 ++ 01_python基础/1_12_函数/practice.py | 145 +++++ 01_python基础/1_13_函数进阶/README.md | 381 +++++++++++++ .../1_13_函数进阶/advanced_functions.py | 100 ++++ 01_python基础/1_13_函数进阶/practice.py | 119 ++++ 01_python基础/1_4_运算符/practice.py | 17 - README.md | 23 +- 11 files changed, 1862 insertions(+), 29 deletions(-) create mode 100644 01_python基础/1_11_集合/README.md create mode 100644 01_python基础/1_11_集合/practice.py create mode 100644 01_python基础/1_11_集合/sets.py create mode 100644 01_python基础/1_12_函数/README.md create mode 100644 01_python基础/1_12_函数/functions.py create mode 100644 01_python基础/1_12_函数/practice.py create mode 100644 01_python基础/1_13_函数进阶/README.md create mode 100644 01_python基础/1_13_函数进阶/advanced_functions.py create mode 100644 01_python基础/1_13_函数进阶/practice.py diff --git a/01_python基础/1_11_集合/README.md b/01_python基础/1_11_集合/README.md new file mode 100644 index 0000000..83ff814 --- /dev/null +++ b/01_python基础/1_11_集合/README.md @@ -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` 判断元素; +- 能正确添加、删除和遍历集合元素; +- 能计算两组集合的交集、并集、差集和对称差集; +- 能判断子集关系; +- 能使用集合完成列表去重; +- 示例和练习均可正常运行。 diff --git a/01_python基础/1_11_集合/practice.py b/01_python基础/1_11_集合/practice.py new file mode 100644 index 0000000..18143af --- /dev/null +++ b/01_python基础/1_11_集合/practice.py @@ -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. 是否理解集合去重可能打乱原列表顺序。 diff --git a/01_python基础/1_11_集合/sets.py b/01_python基础/1_11_集合/sets.py new file mode 100644 index 0000000..d2d6ad3 --- /dev/null +++ b/01_python基础/1_11_集合/sets.py @@ -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}") diff --git a/01_python基础/1_12_函数/README.md b/01_python基础/1_12_函数/README.md new file mode 100644 index 0000000..461a866 --- /dev/null +++ b/01_python基础/1_12_函数/README.md @@ -0,0 +1,300 @@ +# 第 1-12 课:函数 + +## 一、本课目标 + +完成本课后,你将能够: + +1. 理解函数是什么,以及为什么需要函数; +2. 使用 `def` 定义函数; +3. 调用函数并传递参数; +4. 使用返回值把结果交给调用者; +5. 区分“打印结果”和“返回结果”; +6. 使用默认参数和关键字参数; +7. 理解局部变量和全局变量的基本区别; +8. 为简单函数编写文档字符串; +9. 把重复代码整理成可复用的函数。 + +## 二、前置知识 + +- 变量和数据类型; +- 条件判断; +- `for` 循环; +- 字符串、列表、字典和集合; +- 基本的布尔判断。 + +## 三、函数是什么 + +函数(Function)是一段有名字、可以重复执行的代码。 + +例如,下面的代码每次都能完成同一件事: + +```python +def say_hello(): + print("你好,Python!") +``` + +定义函数不会立即执行函数体。只有调用它时,代码才会运行: + +```python +say_hello() +``` + +可以把函数理解为一个“工具盒”: + +- 定义函数:制作工具; +- 调用函数:使用工具; +- 参数:交给工具的材料; +- 返回值:工具加工后的结果。 + +## 四、定义和调用函数 + +基本格式: + +```python +def 函数名(): + 函数体 +``` + +注意: + +1. `def` 是定义函数的关键字; +2. 函数名建议使用英文蛇形命名; +3. 函数体必须缩进; +4. 函数定义后需要通过 `函数名()` 调用。 + +示例: + +```python +def print_separator(): + print("=" * 30) + + +print_separator() +``` + +## 五、参数:把数据交给函数 + +### 5.1 一个参数 + +```python +def greet_user(name): + print(f"你好,{name}!") + + +greet_user("小明") +``` + +`name` 是参数(Parameter),`"小明"` 是调用时传入的实参(Argument)。 + +### 5.2 多个参数 + +```python +def print_agent(name, model): + print(f"Agent:{name},模型:{model}") + + +print_agent("代码助手", "gpt-5") +``` + +参数按位置传递时,顺序很重要。 + +### 5.3 关键字参数 + +也可以明确写出参数名: + +```python +print_agent(model="gpt-5", name="代码助手") +``` + +使用关键字参数后,调用顺序可以调整,可读性也更好。 + +## 六、返回值:把结果交给调用者 + +`return` 用于结束函数执行,并把结果返回给调用者: + +```python +def add_numbers(first_number, second_number): + return first_number + second_number + + +total = add_numbers(3, 5) +print(total) +``` + +`return` 后面的结果可以保存到变量、参与计算或传给其他函数。 + +## 七、打印和返回的区别 + +下面两个函数看起来相似,但用途不同: + +```python +def print_total(first_number, second_number): + print(first_number + second_number) + + +def get_total(first_number, second_number): + return first_number + second_number +``` + +前者只负责显示,调用者不能直接拿到计算结果;后者把结果交给调用者,更适合程序继续处理。 + +```python +result = get_total(3, 5) +print(result * 2) +``` + +如果函数没有写 `return`,Python 会自动返回 `None`,表示“没有结果”。 + +## 八、默认参数 + +可以为参数准备默认值: + +```python +def create_agent(name, model="gpt-5"): + return f"{name} 使用 {model}" + + +print(create_agent("代码助手")) +print(create_agent("搜索助手", "o3")) +``` + +调用时不传 `model`,就使用 `"gpt-5"`;传入了新值,就使用新值。 + +默认参数通常放在普通参数后面。 + +## 九、函数中的条件和循环 + +函数体可以包含前面学过的条件和循环: + +```python +def count_enabled_agents(agents): + enabled_count = 0 + + for agent in agents: + if agent["enabled"]: + enabled_count += 1 + + return enabled_count +``` + +函数的价值之一,就是把一段有明确目的的处理逻辑集中起来。 + +## 十、变量作用域 + +作用域(Scope)表示变量可以被使用的范围。 + +```python +message = "这是全局变量" + + +def show_message(): + local_message = "这是局部变量" + print(message) + print(local_message) + + +show_message() +``` + +- 在函数外定义的变量通常称为全局变量; +- 在函数内定义的变量通常是局部变量; +- 函数执行结束后,局部变量通常不能在函数外直接使用。 + +入门阶段建议:通过参数传入数据,通过 `return` 返回结果,少依赖全局变量。 + +## 十一、文档字符串 + +函数第一行的字符串可以作为文档字符串(Docstring),说明函数的用途: + +```python +def is_agent_enabled(agent): + """判断 Agent 是否处于启用状态。""" + return agent["enabled"] +``` + +文档字符串会帮助自己和其他开发者理解函数。 + +## 十二、运行本课示例 + +进入项目根目录: + +```powershell +cd D:\Code\Python +``` + +运行示例: + +```powershell +python .\01_python基础\1_12_函数\functions.py +``` + +运行练习: + +```powershell +python .\01_python基础\1_12_函数\practice.py +``` + +## 十三、常见错误 + +### 13.1 忘记调用函数 + +只写 `def` 是定义,不会自动执行,必须写 `函数名()`。 + +### 13.2 函数体没有缩进 + +`def` 下一行开始的函数体必须缩进,通常使用四个空格。 + +### 13.3 参数数量不匹配 + +函数需要两个参数却只传一个,会出现 `TypeError`,中文意思是参数数量或类型不正确。 + +### 13.4 把 `print()` 当成 `return` + +`print()` 负责显示,`return` 负责把结果交给调用者。 + +### 13.5 忘记接收返回值 + +函数返回的结果如果后续还要使用,应保存到变量中。 + +### 13.6 过度使用全局变量 + +优先使用参数和返回值传递数据,让函数更容易测试和复用。 + +## 十四、课堂练习 + +打开: + +```text +01_python基础/1_12_函数/practice.py +``` + +本课练习将创建“Agent 文本处理工具箱”,逐步完成: + +1. 无参数问候函数; +2. 带参数的 Agent 信息函数; +3. 返回字符串的函数; +4. 带默认参数的配置函数; +5. 使用条件和循环统计 Agent; +6. 使用函数整理工具权限和模型记录。 + +## 十五、本课小结 + +1. 函数是可重复使用的代码块; +2. `def` 定义函数,调用函数时使用括号; +3. 参数用于输入数据; +4. `return` 用于返回结果; +5. `print()` 和 `return` 的用途不同; +6. 默认参数可以减少重复传值; +7. 局部变量和全局变量的作用范围不同; +8. 函数应尽量职责单一、名称清晰。 + +## 十六、验收标准 + +- 能独立定义并调用函数; +- 能正确传递一个或多个参数; +- 能区分打印和返回; +- 能使用默认参数; +- 能从函数外接收返回值; +- 能使用函数处理列表或字典; +- 示例和练习均可正常运行; +- 函数名和变量名符合英文蛇形命名规范。 diff --git a/01_python基础/1_12_函数/functions.py b/01_python基础/1_12_函数/functions.py new file mode 100644 index 0000000..e0d8593 --- /dev/null +++ b/01_python基础/1_12_函数/functions.py @@ -0,0 +1,56 @@ +# 第 1-12 课示例:函数 +# +# 本文件演示函数的定义、调用、参数、返回值、默认参数和实际数据处理。 + + +def print_separator(): + """输出分隔线,让命令行结果更容易阅读。""" + print("=" * 30) + + +def greet_user(name): + """根据姓名输出问候语。""" + print(f"你好,{name}!") + + +def build_agent_description(name, model="gpt-5"): + """返回 Agent 的文字描述,而不是直接打印。""" + return f"Agent:{name},模型:{model}" + + +def count_enabled_agents(agents): + """统计列表中 enabled 为 True 的 Agent 数量。""" + enabled_count = 0 + + for agent in agents: + if agent["enabled"]: + enabled_count += 1 + + return enabled_count + + +def get_available_tools(agent): + """返回 Agent 的工具列表;没有 tools 时返回空列表。""" + return agent.get("tools", []) + + +print_separator() +greet_user("Python 学习者") + +print_separator() +print(build_agent_description("代码助手")) +print(build_agent_description("搜索助手", model="o3")) + +print_separator() +agents = [ + {"name": "代码助手", "enabled": True, "tools": ["搜索", "计算"]}, + {"name": "搜索助手", "enabled": False, "tools": ["搜索"]}, + {"name": "写作助手", "enabled": True, "tools": ["写作"]}, +] + +enabled_count = count_enabled_agents(agents) +print(f"启用的 Agent 数量:{enabled_count}") + +for agent in agents: + tools = get_available_tools(agent) + print(f"{agent['name']} 的工具:{tools}") diff --git a/01_python基础/1_12_函数/practice.py b/01_python基础/1_12_函数/practice.py new file mode 100644 index 0000000..0582635 --- /dev/null +++ b/01_python基础/1_12_函数/practice.py @@ -0,0 +1,145 @@ +# 第 1-12 课课堂练习:Agent 文本处理工具箱 +# +# 完成要求: +# 1. 根据注释定义和调用函数,练习参数与返回值。 +# 2. 使用有意义的英文蛇形函数名和变量名。 +# 3. 函数体使用四个空格缩进。 +# 4. 不要删除题目注释。 +# 5. 完成后运行本文件并核对预期结果。 + + +# 练习一:定义并调用一个负责输出问候语的函数。 +# 1. 定义 greet_user(name) 函数,参数 name 表示需要问候的姓名。 +# 2. 函数内部使用 print() 输出“你好,{name}!”,本题不需要使用 return。 +# 3. 调用函数时传入字符串“Python 学习者”。 +# 4. 预期输出:你好,Python 学习者! +# 可参考 functions.py 中 greet_user(name) 的写法。 + + +# 练习二:定义一个用于生成 Agent 描述文本的函数。 +# 1. 定义 build_agent_description(name, model) 函数。 +# 参数 name 表示 Agent 名称,参数 model 表示模型名称。 +# 2. 函数内部不要直接输出,而是使用 return 返回字符串: +# “Agent:{name},模型:{model}”。 +# 3. 使用“代码助手”和“gpt-5”作为参数调用函数。 +# 4. 把返回值保存到变量 description,再使用 print(description) 输出。 +# 5. 预期输出:Agent:代码助手,模型:gpt-5 +# 可参考 functions.py 中 build_agent_description(name, model) 的写法。 + + + +# 练习三:定义一个计算两个数字之和的函数。 +# 1. 定义 get_total(first_number, second_number) 函数,两个参数都接收数字。 +# 2. 在函数内部计算 first_number + second_number,并使用 return 返回计算结果。 +# 3. 调用函数计算 12 和 8,把返回值保存到变量 total。 +# 4. 使用 print(total) 输出结果,预期输出:20。 +# 注意:本题要练习返回值,因此不要只在函数内部 print() 计算结果。 + + + +# 练习四:定义一个带默认参数的 Agent 描述函数。 +# 1. 定义 build_agent_description_with_default(name, model="gpt-5") 函数。 +# 2. 函数使用 return 返回“Agent:{name},模型:{model}”。 +# 3. 第一次只传入 name="代码助手",把返回值保存并输出;此时 model 自动使用“gpt-5”。 +# 4. 第二次传入 name="代码助手"和关键字参数 model="o3",再保存并输出返回值。 +# 5. 两次预期输出分别为: +# Agent:代码助手,模型:gpt-5 +# Agent:代码助手,模型:o3 +# 可参考 functions.py 中默认参数和关键字参数的示例。 + + + +# 练习五:定义一个安全读取 Agent 工具列表的函数。 +# 1. 定义 get_agent_tools(agent) 函数,参数 agent 接收一个字典。 +# 2. 函数内部使用 return agent.get("tools", []): +# 字典存在 tools 键时返回对应的列表,不存在时返回默认的空列表 []。 +# 3. 创建第一个测试字典: +# {"name": "代码助手", "tools": ["搜索", "计算器"]} +# 4. 创建第二个测试字典:{"name": "聊天助手"},它没有 tools 键。 +# 5. 分别调用函数并用 print() 输出返回值。 +# 6. 两次预期输出分别为:["搜索", "计算器"] 和 []。 +# 可参考 functions.py 中 get_available_tools(agent) 的写法。 + + + +# 练习六:定义一个统计已启用 Agent 数量的函数。 +# 1. 定义 count_enabled_agents(agents) 函数,参数 agents 接收“由字典组成的列表”。 +# 2. 在函数内先创建计数变量 enabled_count,并把初始值设为 0。 +# 3. 遍历 agents;如果当前字典的 agent["enabled"] 为 True,就把计数加 1。 +# 4. 遍历结束后,使用 return 返回 enabled_count。不要遇到 False 就提前结束循环。 +# 5. 使用下面三条数据测试: +# {"name": "代码助手", "enabled": True} +# {"name": "聊天助手", "enabled": False} +# {"name": "搜索助手", "enabled": True} +# 6. 保存并输出函数返回值,预期输出:2。 +# 可参考 functions.py 中 count_enabled_agents(agents) 的写法。 + + + +# 练习七:定义一个获取所有已启用 Agent 名称的函数。 +# 1. 定义 get_enabled_agent_names(agents) 函数,agents 的数据结构与练习六相同。 +# 2. 在函数内创建空列表 enabled_names,用于保存符合条件的名称。 +# 3. 遍历 agents;当 agent["enabled"] 为 True 时,把 agent["name"] 添加到列表。 +# 4. 遍历结束后,使用 return 返回 enabled_names。 +# 5. 使用练习六给出的三条 Agent 数据调用函数,并使用 print() 输出返回值。 +# 6. 预期输出:["代码助手", "搜索助手"],停用的“聊天助手”不应出现在结果中。 + +# 练习八:定义一个判断 Agent 是否具备全部必需工具的函数。 +# 1. 定义 has_required_tools(agent, required_tools) 函数: +# agent 接收 Agent 字典,required_tools 接收“必需工具集合”。 +# 2. 使用 agent.get("tools", []) 读取工具列表,再用 set() 转换为集合, +# 并把这个集合保存到局部变量 agent_tools。 +# 3. 使用 required_tools <= agent_tools 判断“必需工具集合是否为 Agent 工具集合的子集”。 +# 只有每一个必需工具都存在时,表达式才会得到 True。 +# 4. 使用 return 返回判断结果,不要只在函数内部输出。 +# 5. 创建测试 Agent: +# {"name": "代码助手", "tools": ["搜索", "计算器", "终端"]} +# 6. 第一次传入必需工具集合 {"搜索", "终端"},保存并输出结果,预期为 True。 +# 7. 第二次传入必需工具集合 {"搜索", "数据库"},保存并输出结果,预期为 False。 +# 可回顾上一课“集合”中的子集判断,也可参考本课练习五的字典读取方式。 + + +# 练习九:定义一个逐行输出 Agent 报告的函数。 +# 1. 定义 print_agent_report(agents) 函数,agents 接收“由字典组成的列表”。 +# 2. 每个字典都包含 name、enabled 和 tools 三个键,例如: +# {"name": "代码助手", "enabled": True, "tools": ["搜索", "终端"]} +# {"name": "聊天助手", "enabled": False, "tools": []} +# 3. 遍历 agents,根据 enabled 的布尔值生成中文状态:True 对应“启用”,False 对应“停用”。 +# 4. 使用 len(agent["tools"]) 取得工具数量。 +# 5. 在函数内部使用 print() 输出每个 Agent,本题只负责显示报告,不需要 return。 +# 6. 调用函数后,预期输出: +# 代码助手:启用,工具数量:2 +# 聊天助手:停用,工具数量:0 + + +# 练习十:定义一个对模型使用记录去重并排序的函数。 +# 1. 定义 normalize_model_history(model_history) 函数,参数接收模型名称列表。 +# 2. 先使用 set(model_history) 去除重复名称。 +# 3. 再把去重后的集合传给 sorted();sorted() 会返回一个排好序的新列表。 +# 4. 使用 return 返回这个新列表,不要只在函数内部输出。 +# 5. 使用 ["gpt-5", "o3", "gpt-5", "claude"] 调用函数,保存并输出返回值。 +# 6. 预期输出:["claude", "gpt-5", "o3"]。 +# 可回顾上一课“集合”中的去重方式和 sorted() 的用法。 + + +# 预期核心结果: +# greet_user() 能输出问候语; +# build_agent_description() 能返回可保存的字符串; +# get_total(12, 8) 返回 20; +# 默认参数调用时使用 gpt-5,关键字参数调用时使用 o3; +# 没有 tools 的 Agent 返回空列表; +# count_enabled_agents() 返回 2; +# get_enabled_agent_names() 只返回启用 Agent 的名称; +# 权限满足判断返回 True; +# 报告函数能正确输出每个 Agent 的状态和工具数量; +# 模型记录去重后按排序结果返回。 + + +# 完成后进行自查: +# 1. 是否使用 def 定义函数; +# 2. 是否正确传递位置参数和关键字参数; +# 3. 需要继续使用的结果是否使用 return; +# 4. 是否区分 print() 和 return; +# 5. 默认参数是否放在普通参数后面; +# 6. 函数内的局部变量是否没有误当作全局变量; +# 7. 函数是否尽量只负责一个清晰的任务。 diff --git a/01_python基础/1_13_函数进阶/README.md b/01_python基础/1_13_函数进阶/README.md new file mode 100644 index 0000000..a58dbb5 --- /dev/null +++ b/01_python基础/1_13_函数进阶/README.md @@ -0,0 +1,381 @@ +# 第 1-13 课:函数进阶 + +## 一、本课目标 + +完成本课后,你将能够: + +1. 使用 `return` 一次返回多个结果; +2. 使用提前返回减少不必要的嵌套; +3. 使用 `*args` 接收任意数量的位置参数; +4. 使用 `**kwargs` 接收任意数量的关键字参数; +5. 使用 `*` 和 `**` 在调用函数时解包数据; +6. 根据不同任务选择普通参数、`*args` 或 `**kwargs`; +7. 继续练习让函数保持清晰、职责单一。 + +## 二、前置知识 + +学习本课前,需要理解: + +- 如何使用 `def` 定义函数; +- 如何调用函数; +- 位置参数、关键字参数和默认参数; +- `print()` 与 `return` 的区别; +- 列表、元组和字典; +- 条件判断和循环。 + +## 三、一次返回多个结果 + +一个函数可以在 `return` 后面写多个值: + +```python +def get_agent_summary(agent): + return agent["name"], len(agent.get("tools", [])) + + +agent_name, tool_count = get_agent_summary({ + "name": "代码助手", + "tools": ["搜索", "终端"], +}) + +print(agent_name) +print(tool_count) +``` + +Python 实际上会先把多个返回值组合成一个元组,再把元组解包给多个变量。 + +也可以只用一个变量接收: + +```python +summary = get_agent_summary({"name": "聊天助手", "tools": []}) +print(summary) +print(type(summary)) +``` + +此时 `summary` 是元组,例如 `("聊天助手", 0)`。 + +## 四、提前返回 + +`return` 不只负责返回结果,还会立即结束当前函数。 + +```python +def get_agent_status(agent): + if not agent.get("enabled", False): + return "停用" + + return "启用" +``` + +如果 Agent 没有启用,函数执行第一个 `return` 后就结束,不会继续执行下面的代码。 + +这种写法称为提前返回(Early Return)。它适合先处理无效数据或特殊情况,避免出现太多层缩进。 + +## 五、使用 `*args` 接收多个位置参数 + +有时无法提前确定调用者会传入几个位置参数,这时可以使用 `*args`: + +```python +def count_tools(*tools): + return len(tools) + + +print(count_tools("搜索")) +print(count_tools("搜索", "终端", "计算器")) +``` + +这里的 `args` 是 arguments 的缩写,表示“多个参数”。 + +需要注意: + +- 参数名前面的 `*` 才是关键; +- `args` 是约定俗成的名称,也可以换成其他名称; +- 函数内部的 `tools` 是一个元组; +- 即使没有传入任何工具,`tools` 也是空元组。 + +```python +def show_tools(*tools): + print(tools) + print(type(tools)) +``` + +## 六、普通参数和 `*args` 一起使用 + +普通参数可以写在 `*args` 前面: + +```python +def build_tool_message(agent_name, *tools): + return f"{agent_name} 拥有 {len(tools)} 个工具" + + +message = build_tool_message("代码助手", "搜索", "终端") +print(message) +``` + +调用时,第一个位置参数交给 `agent_name`,剩余位置参数都被收集到 `tools` 元组中。 + +## 七、使用 `**kwargs` 接收多个关键字参数 + +如果无法提前确定调用者会传入哪些关键字参数,可以使用 `**kwargs`: + +```python +def build_agent_config(**config): + return config + + +agent_config = build_agent_config( + name="代码助手", + model="gpt-5", + enabled=True, +) + +print(agent_config) +``` + +`kwargs` 是 keyword arguments 的缩写,中文可理解为“多个关键字参数”。 + +函数内部的 `config` 是字典: + +```python +{ + "name": "代码助手", + "model": "gpt-5", + "enabled": True, +} +``` + +同样,参数名前面的两个星号 `**` 才是关键,`kwargs` 只是常见命名。 + +## 八、普通参数和 `**kwargs` 一起使用 + +```python +def create_agent(name, **settings): + return { + "name": name, + "settings": settings, + } + + +agent = create_agent("代码助手", model="gpt-5", enabled=True) +print(agent) +``` + +`name` 接收普通参数,其他关键字参数被收集到 `settings` 字典中。 + +## 九、调用函数时使用 `*` 解包列表或元组 + +星号也可以出现在函数调用中。此时它表示把列表或元组中的元素依次作为位置参数传入。 + +```python +def add_three_numbers(first, second, third): + return first + second + third + + +numbers = [10, 20, 30] +total = add_three_numbers(*numbers) +print(total) +``` + +上面的调用相当于: + +```python +total = add_three_numbers(10, 20, 30) +``` + +元素数量必须与函数所需的位置参数数量匹配,否则会产生 `TypeError`。 + +## 十、调用函数时使用 `**` 解包字典 + +两个星号可以把字典解包成关键字参数: + +```python +def describe_agent(name, model): + return f"{name} 使用 {model}" + + +agent_data = { + "name": "代码助手", + "model": "gpt-5", +} + +description = describe_agent(**agent_data) +print(description) +``` + +上面的调用相当于: + +```python +description = describe_agent(name="代码助手", model="gpt-5") +``` + +字典的键必须与函数参数名一致。 + +## 十一、如何选择参数形式 + +### 使用普通参数 + +参数数量固定、含义明确时,优先使用普通参数: + +```python +def get_total(first_number, second_number): + return first_number + second_number +``` + +### 使用 `*args` + +需要接收数量不固定的同类位置参数时使用: + +```python +def count_tools(*tools): + return len(tools) +``` + +### 使用 `**kwargs` + +需要接收数量或名称不固定的配置项时使用: + +```python +def build_config(**config): + return config +``` + +不要为了显得代码高级而强行使用 `*args` 或 `**kwargs`。参数固定时,普通参数通常更清楚。 + +## 十二、完整示例 + +本课示例文件为: + +```text +01_python基础/1_13_函数进阶/advanced_functions.py +``` + +示例会依次演示: + +1. 返回多个结果; +2. 提前返回; +3. 使用 `*args`; +4. 使用 `**kwargs`; +5. 解包列表和字典后调用函数。 + +## 十三、运行方法 + +在项目根目录执行: + +```powershell +python .\01_python基础\1_13_函数进阶\advanced_functions.py +``` + +运行练习: + +```powershell +python .\01_python基础\1_13_函数进阶\practice.py +``` + +## 十四、示例运行结果 + +```text +一、返回多个结果 +Agent 名称:代码助手 +工具数量:2 +============================== +二、提前返回 +启用 +停用 +============================== +三、任意数量的位置参数 +工具数量:3 +============================== +四、任意数量的关键字参数 +{'name': '代码助手', 'model': 'gpt-5', 'enabled': True} +============================== +五、调用时解包数据 +数字总和:60 +代码助手 使用 gpt-5 +``` + +字典的显示格式可能因环境而略有差异,但键和值应当一致。 + +## 十五、关键代码解析 + +```python +def count_tools(*tools): + return len(tools) +``` + +执行顺序如下: + +1. 调用者传入零个或多个位置参数; +2. `*` 把这些参数收集到 `tools`; +3. `tools` 在函数内部是元组; +4. `len()` 统计元组中的元素数量; +5. `return` 把数量交给调用者。 + +```python +def build_agent_config(**config): + return config +``` + +执行顺序如下: + +1. 调用者传入零个或多个关键字参数; +2. `**` 把参数名称和值收集到 `config`; +3. `config` 在函数内部是字典; +4. 函数把字典返回给调用者。 + +## 十六、常见错误 + +### 16.1 混淆 `*args` 和 `**kwargs` + +- `*args` 收集位置参数,函数内部得到元组; +- `**kwargs` 收集关键字参数,函数内部得到字典。 + +### 16.2 忘记星号 + +`args` 和 `kwargs` 本身只是普通名称。真正产生收集效果的是 `*` 和 `**`。 + +### 16.3 解包后的参数数量不匹配 + +如果函数需要三个参数,列表却只有两个元素,会产生 `TypeError`,表示调用时提供的参数数量不正确。 + +### 16.4 字典键与参数名不一致 + +使用 `**dictionary` 调用函数时,字典键必须能对应函数参数名。 + +### 16.5 在 `return` 后继续编写必须执行的代码 + +函数执行到 `return` 就会结束,写在同一执行路径后面的代码不会运行。 + +### 16.6 所有函数都使用可变参数 + +固定且明确的数据应继续使用普通参数。过度使用可变参数会降低可读性。 + +## 十七、课堂练习 + +打开: + +```text +01_python基础/1_13_函数进阶/practice.py +``` + +练习题已经明确提供输入数据、实现步骤、返回要求和预期结果。请先独立完成,再进行验证。 + +## 十八、本课小结 + +1. `return value1, value2` 可以返回多个结果; +2. 多个返回值实际会组合成元组; +3. 提前返回可以尽早结束函数; +4. `*args` 收集位置参数并形成元组; +5. `**kwargs` 收集关键字参数并形成字典; +6. 调用函数时,`*` 可以解包列表或元组; +7. 调用函数时,`**` 可以解包字典; +8. 参数固定时应优先使用普通参数。 + +## 十九、验收标准 + +- 能正确接收函数的多个返回值; +- 能解释 `return` 为什么会结束函数; +- 能使用 `*args` 接收不同数量的位置参数; +- 能说明 `*args` 在函数内部是元组; +- 能使用 `**kwargs` 接收关键字参数; +- 能说明 `**kwargs` 在函数内部是字典; +- 能使用 `*` 解包列表或元组后调用函数; +- 能使用 `**` 解包字典后调用函数; +- 示例程序和练习程序可以正常运行。 diff --git a/01_python基础/1_13_函数进阶/advanced_functions.py b/01_python基础/1_13_函数进阶/advanced_functions.py new file mode 100644 index 0000000..6ec3d23 --- /dev/null +++ b/01_python基础/1_13_函数进阶/advanced_functions.py @@ -0,0 +1,100 @@ +# 第 1-13 课示例:函数进阶 +# +# 本文件依次演示: +# 1. 返回多个结果; +# 2. 提前返回; +# 3. 使用 *args 接收任意数量的位置参数; +# 4. 使用 **kwargs 接收任意数量的关键字参数; +# 5. 在调用函数时解包列表和字典。 + + +def print_separator(): + """输出分隔线,让不同示例的结果更容易区分。""" + print("=" * 30) + + +def get_agent_summary(agent): + """返回 Agent 名称和工具数量。""" + agent_name = agent["name"] + tool_count = len(agent.get("tools", [])) + return agent_name, tool_count + + +def get_agent_status(agent): + """根据 Agent 的 enabled 配置返回中文状态。""" + # get() 的第二个参数 False 是默认值。 + # 如果字典中没有 enabled,就把它当作未启用处理。 + if not agent.get("enabled", False): + return "停用" + + # 前面的条件成立时,函数已经提前结束。 + # 因此执行到这里时,可以确定 Agent 已经启用。 + return "启用" + + +def count_tools(*tools): + """返回调用者传入的工具数量。""" + # tools 在函数内部是元组,可以使用 len() 统计元素数量。 + return len(tools) + + +def build_agent_config(**config): + """把关键字参数收集成 Agent 配置字典并返回。""" + # config 在函数内部是字典。 + return config + + +def add_three_numbers(first, second, third): + """返回三个数字的和。""" + return first + second + third + + +def describe_agent(name, model): + """返回包含 Agent 名称和模型的描述文本。""" + return f"{name} 使用 {model}" + + +print("一、返回多个结果") +example_agent = { + "name": "代码助手", + "tools": ["搜索", "终端"], +} +agent_name, tool_count = get_agent_summary(example_agent) +print(f"Agent 名称:{agent_name}") +print(f"工具数量:{tool_count}") + +print_separator() + +print("二、提前返回") +print(get_agent_status({"name": "代码助手", "enabled": True})) +print(get_agent_status({"name": "聊天助手", "enabled": False})) + +print_separator() + +print("三、任意数量的位置参数") +available_tool_count = count_tools("搜索", "终端", "计算器") +print(f"工具数量:{available_tool_count}") + +print_separator() + +print("四、任意数量的关键字参数") +agent_config = build_agent_config( + name="代码助手", + model="gpt-5", + enabled=True, +) +print(agent_config) + +print_separator() + +print("五、调用时解包数据") +numbers = [10, 20, 30] +total = add_three_numbers(*numbers) +print(f"数字总和:{total}") + +agent_data = { + "name": "代码助手", + "model": "gpt-5", +} +description = describe_agent(**agent_data) +print(description) diff --git a/01_python基础/1_13_函数进阶/practice.py b/01_python基础/1_13_函数进阶/practice.py new file mode 100644 index 0000000..b658ab0 --- /dev/null +++ b/01_python基础/1_13_函数进阶/practice.py @@ -0,0 +1,119 @@ +# 第 1-13 课课堂练习:Agent 函数工具箱进阶 +# +# 完成要求: +# 1. 按照每道题给出的函数名、参数、测试数据和预期结果完成代码。 +# 2. 需要继续使用的结果必须通过 return 返回,再由调用者使用 print() 输出。 +# 3. 使用有意义的英文蛇形函数名和变量名。 +# 4. 函数体使用四个空格缩进。 +# 5. 不要删除题目注释。 +# 6. 完成后运行本文件,并逐项核对预期结果。 + + +# 练习一:定义一个返回多个结果的函数。 +# 1. 定义 get_model_summary(models) 函数,参数 models 接收模型名称列表。 +# 2. 函数使用 len(models) 得到模型数量。 +# 3. 使用 models[0] 得到第一个模型名称。 +# 4. 使用一个 return 同时返回“模型数量”和“第一个模型名称”。 +# 5. 使用 ["gpt-5", "o3", "claude"] 调用函数,并用两个变量接收返回值。 +# 6. 分别输出两个变量,预期输出:3 和 gpt-5。 + + +# 练习二:观察多个返回值的真实数据类型。 +# 1. 再次调用练习一的 get_model_summary()。 +# 2. 这次只使用一个变量 summary 接收全部返回值。 +# 3. 输出 summary 和 type(summary)。 +# 4. 预期 summary 为 (3, "gpt-5"),类型为 tuple。 + + +# 练习三:使用提前返回处理无效数据。 +# 1. 定义 calculate_average(scores) 函数,scores 接收分数列表。 +# 2. 如果 scores 是空列表,立即使用 return 返回 0。 +# 3. 如果列表非空,返回 sum(scores) / len(scores)。 +# sum() 用于计算列表中所有数字的总和。 +# 4. 第一次使用 [80, 90, 100] 调用,保存并输出结果,预期为 90.0。 +# 5. 第二次使用空列表 [] 调用,保存并输出结果,预期为 0。 + + +# 练习四:使用 *args 接收任意数量的工具。 +# 1. 定义 count_agent_tools(*tools) 函数。 +# 2. 函数内部使用 len(tools) 统计工具数量,并使用 return 返回。 +# 3. 调用 count_agent_tools("搜索", "终端", "计算器"),保存并输出结果。 +# 4. 再调用一次 count_agent_tools(),本次不传任何工具。 +# 5. 两次预期输出分别为 3 和 0。 +# 可参考 advanced_functions.py 中 count_tools(*tools) 的写法。 + + +# 练习五:确认 *args 在函数内部是元组。 +# 1. 定义 collect_models(*models) 函数。 +# 2. 函数直接使用 return 返回 models。 +# 3. 传入 "gpt-5"、"o3" 和 "claude" 调用函数,把返回值保存到 collected_models。 +# 4. 输出 collected_models 和它的类型。 +# 5. 预期输出内容为 ("gpt-5", "o3", "claude"),类型为 tuple。 + + +# 练习六:组合普通参数和 *args。 +# 1. 定义 build_agent_tool_message(agent_name, *tools) 函数。 +# 2. 使用 return 返回:"{agent_name} 拥有 {len(tools)} 个工具"。 +# 3. 使用 "代码助手"、"搜索"、"终端" 调用函数,保存并输出返回值。 +# 4. 预期输出:代码助手 拥有 2 个工具。 + + +# 练习七:使用 **kwargs 收集关键字参数。 +# 1. 定义 build_runtime_config(**settings) 函数。 +# 2. 函数直接使用 return 返回 settings。 +# 3. 使用以下三个关键字参数调用函数: +# model="gpt-5"、timeout=30、enabled=True。 +# 4. 把返回值保存到 runtime_config,并输出它和它的类型。 +# 5. 预期字典包含三个对应键值,类型为 dict。 +# 可参考 advanced_functions.py 中 build_agent_config(**config) 的写法。 + + +# 练习八:组合普通参数和 **kwargs。 +# 1. 定义 create_agent(name, **settings) 函数。 +# 2. 函数返回一个字典,结构必须是: +# {"name": name, "settings": settings} +# 3. 使用 name="代码助手"、model="gpt-5"、enabled=True 调用函数。 +# 4. 保存并输出返回值。 +# 5. 预期结果中的 name 为“代码助手”,settings 是包含 model 和 enabled 的字典。 + + +# 练习九:使用 * 解包列表后调用函数。 +# 1. 定义 multiply_three_numbers(first, second, third) 函数。 +# 2. 函数使用 return 返回三个数字的乘积。 +# 3. 创建列表 numbers = [2, 3, 4]。 +# 4. 使用 multiply_three_numbers(*numbers) 调用函数,而不是手动写三个参数。 +# 5. 保存并输出返回值,预期输出:24。 + + +# 练习十:使用 ** 解包字典后调用函数。 +# 1. 定义 build_model_message(name, model) 函数。 +# 2. 函数使用 return 返回:"{name} 使用模型 {model}"。 +# 3. 创建字典: +# agent_data = {"name": "搜索助手", "model": "o3"} +# 4. 使用 build_model_message(**agent_data) 调用函数。 +# 5. 保存并输出返回值,预期输出:搜索助手 使用模型 o3。 + + +# 预期核心结果: +# 练习一分别得到 3 和 gpt-5; +# 练习二确认多个返回值组成 tuple; +# 非空分数列表的平均分为 90.0,空列表结果为 0; +# count_agent_tools() 分别返回 3 和 0; +# collect_models() 返回元组; +# Agent 工具消息显示 2 个工具; +# **kwargs 收集到的数据类型为 dict; +# create_agent() 返回包含 name 和 settings 的嵌套字典; +# 三个数字的乘积为 24; +# 字典解包后生成“搜索助手 使用模型 o3”。 + + +# 完成后进行自查: +# 1. 多个返回值是否使用多个变量正确接收; +# 2. 只用一个变量接收多个返回值时,是否得到元组; +# 3. 空列表是否通过提前返回避免了除以零; +# 4. *args 在函数内部是否被当作元组使用; +# 5. **kwargs 在函数内部是否被当作字典使用; +# 6. 普通参数是否写在 *args 或 **kwargs 前面; +# 7. 调用时的 * 是否正确解包列表; +# 8. 调用时的 ** 是否正确解包字典; +# 9. 需要继续使用的计算结果是否通过 return 返回。 diff --git a/01_python基础/1_4_运算符/practice.py b/01_python基础/1_4_运算符/practice.py index 8c186d8..64d5867 100644 --- a/01_python基础/1_4_运算符/practice.py +++ b/01_python基础/1_4_运算符/practice.py @@ -65,20 +65,3 @@ # 3. 是否正确使用了 and 和 not; # 4. += 是否更新了原变量; # 5. 所有计算结果是否与手工推算一致。 - -# 计划学习总天数:30 -# 已经完成的学习天数:7 -# 每天计划学习的小时数:2.5 -# 4 -# ============================== -# 1. 计划总天数和已完成天数: 30,7 -# 2. 剩余天数:23 -# 3. 完整星期数和额外天数:4,2 -# 4. 计划总学习小时数和已完成学习小时数:75.0,17.5 -# has_started=True -# is_plan_finished=False -# has_remaining_days=True -# is_in_progress=True -# completed_tasks=4 -# -# 进程已结束,退出代码为 0 diff --git a/README.md b/README.md index 8068f0e..d961231 100644 --- a/README.md +++ b/README.md @@ -189,11 +189,12 @@ Python/ ## 当前学习进度 - 当前阶段:第一阶段——Python 基础语法。 -- 当前课程:`1_10_字典`。 -- 当前状态:第十课学习中。 -- 已完成课程:`1_1_hello_world` 至 `1_9_元组`。 -- 已创建课程目录:`01_python基础/1_1_hello_world/` 至 `01_python基础/1_10_字典/`。 -- 下一步:阅读第十课讲义、运行字典示例并完成课堂练习。 +- 当前课程:`1_13_函数进阶`。 +- 当前状态:第 1~13 课全部完成。 +- 已完成课程:`1_1_hello_world` 至 `1_13_函数进阶`。 +- 学习中的课程:暂无。 +- 已创建课程目录:`01_python基础/1_1_hello_world/` 至 `01_python基础/1_13_函数进阶/`。 +- 下一步:进行第一阶段知识复习,并准备 Python 基础综合项目。 ## 建议环境 @@ -208,11 +209,9 @@ Python/ ## 下一步 -下一课将学习: +第 1~13 课已经完成。接下来将进行: -1. Python 是什么; -2. 程序、编程语言和解释器分别是什么; -3. 如何检查电脑是否已经安装 Python; -4. 如何安装并验证 Python; -5. 如何创建和运行第一个 `hello_world.py` 程序; -6. 如何理解第一行 Python 代码。 +1. 回顾变量、条件判断、循环和常用数据结构; +2. 回顾函数、参数和返回值; +3. 完成 Python 基础阶段测试; +4. 开始 Python 基础综合项目。