feat(python基础): 完成基础综合项目

This commit is contained in:
zhiye.sun
2026-08-03 17:42:04 +08:00
parent 298e5b46ea
commit 42baf5d317
5 changed files with 706 additions and 127 deletions

View File

@@ -0,0 +1,366 @@
# 第 1-14 课Python 基础综合项目
## 一、项目名称
命令行 Agent 管理系统。
命令行程序是直接在终端中运行和操作的程序。本项目不会创建网页界面,而是通过数字菜单接收用户选择。
## 二、为什么要做综合项目
前面的课程分别学习了变量、条件判断、循环、数据结构和函数。单独完成一道小题,只需要使用其中一个知识点;真实程序通常需要把多个知识点组合起来。
本项目用于检验你能否:
1. 把一个较大的需求拆分成多个小功能;
2. 选择合适的数据结构保存信息;
3. 使用函数组织重复逻辑;
4. 使用循环让菜单持续运行;
5. 使用条件判断处理不同操作;
6. 对用户输入进行基本检查;
7. 独立完成一个可以反复操作的命令行程序。
## 三、前置知识
开始前应当掌握:
- `print()``input()`
- 字符串、整数和布尔值;
- 比较运算与逻辑运算;
- `if...elif...else`
- `for``while` 循环;
- 列表、字典和集合;
- 函数、参数和返回值;
- `*args``**kwargs` 的基本含义。
本项目主要使用普通参数,不会为了展示高级语法而强行使用 `*args``**kwargs`
## 四、项目最终功能
程序启动后显示以下菜单:
```text
==============================
命令行 Agent 管理系统
1. 查看全部 Agent
2. 新增 Agent
3. 修改 Agent 状态
4. 删除 Agent
5. 查看 Agent 工具
0. 退出程序
==============================
```
用户输入菜单编号后,程序执行对应功能:
- 输入 `1`:查看全部 Agent
- 输入 `2`:新增 Agent
- 输入 `3`:启用或停用 Agent
- 输入 `4`:删除 Agent
- 输入 `5`:查看指定 Agent 的工具;
- 输入 `0`:结束程序;
- 输入其他内容:显示“无效选项,请重新输入。”。
## 五、数据结构设计
所有 Agent 使用列表保存:
```python
agents = [
{
"name": "代码助手",
"model": "gpt-5",
"enabled": True,
"tools": ["搜索", "终端"],
},
{
"name": "聊天助手",
"model": "o3",
"enabled": False,
"tools": ["搜索"],
},
]
```
选择这种结构的原因:
- 列表适合保存数量可以增加或减少的多条 Agent 记录;
- 每个 Agent 有多个不同含义的字段,适合使用字典;
- `tools` 是一组可以按顺序展示的工具,适合使用列表。
## 六、程序功能拆分
不要把所有代码都写进一个 `while` 循环。项目应拆分为以下函数。
### 6.1 `print_menu()`
职责:输出操作菜单。
- 参数:无;
- 返回值:无;
- 主要操作:使用多条 `print()` 输出菜单。
### 6.2 `print_agents(agents)`
职责:输出全部 Agent。
- 参数Agent 列表;
- 返回值:无;
- 空列表时输出“当前没有 Agent。”
- 非空时输出每个 Agent 的编号、名称、模型和状态。
预期格式:
```text
1. 代码助手模型gpt-5状态启用
2. 聊天助手模型o3状态停用
```
### 6.3 `find_agent_by_name(agents, name)`
职责:按名称查找 Agent。
- 参数Agent 列表和需要查找的名称;
- 找到时:返回对应的 Agent 字典;
- 未找到时:返回 `None`
- 本函数只负责查找,不负责输出提示。
### 6.4 `add_agent(agents)`
职责:接收输入并新增 Agent。
执行顺序:
1. 输入 Agent 名称,并使用 `strip()` 清理两侧空白;
2. 名称为空时输出“Agent 名称不能为空。”并结束本次操作;
3. 调用 `find_agent_by_name()` 检查名称是否重复;
4. 名称重复时输出“该 Agent 已存在。”并结束本次操作;
5. 输入模型名称;
6. 输入工具,多个工具使用英文逗号分隔;
7. 使用 `split(",")` 拆分工具;
8. 清理每个工具两侧空白,并去掉空字符串;
9. 创建 Agent 字典,新 Agent 默认启用;
10. 使用 `append()` 加入列表并输出成功提示。
例如输入:
```text
Agent 名称:搜索助手
模型名称gpt-5
工具:搜索,网页浏览
```
新增后的字典应为:
```python
{
"name": "搜索助手",
"model": "gpt-5",
"enabled": True,
"tools": ["搜索", "网页浏览"],
}
```
### 6.5 `change_agent_status(agents)`
职责:修改指定 Agent 的启用状态。
执行顺序:
1. 输入 Agent 名称;
2. 调用 `find_agent_by_name()` 查找;
3. 未找到时输出“未找到该 Agent。”
4. 找到时使用 `not` 反转 `enabled`
5. 输出修改后的中文状态。
### 6.6 `delete_agent(agents)`
职责:删除指定 Agent。
执行顺序:
1. 输入 Agent 名称;
2. 调用 `find_agent_by_name()` 查找;
3. 未找到时输出“未找到该 Agent。”
4. 找到时使用 `remove()` 删除整个 Agent 字典;
5. 输出“Agent 已删除。”。
### 6.7 `print_agent_tools(agents)`
职责:输出指定 Agent 的工具。
- 未找到 Agent 时输出“未找到该 Agent。”
- 工具列表为空时输出“该 Agent 暂无工具。”;
- 有工具时按编号逐行输出。
预期格式:
```text
代码助手的工具:
1. 搜索
2. 终端
```
### 6.8 `main()`
职责:组织程序主流程。
执行顺序:
1. 创建初始 Agent 列表;
2. 使用 `while True` 持续显示菜单;
3. 使用 `input()` 接收菜单选项;
4. 使用 `if...elif...else` 分发功能;
5. 用户输入 `0` 时输出结束提示并使用 `break` 退出循环。
## 七、完整示例
示例文件:
```text
01_python基础/1_14_python基础综合项目/agent_manager.py
```
示例是完整可运行版本。建议先阅读讲义,再运行示例了解程序行为,最后关闭示例文件,独立完成 `practice.py`
## 八、运行方法
在项目根目录执行示例:
```powershell
python .\01_python基础\1_14_python基础综合项目\agent_manager.py
```
运行自己的项目练习:
```powershell
python .\01_python基础\1_14_python基础综合项目\practice.py
```
程序等待输入时,在终端输入菜单编号并按回车。
## 九、建议开发顺序
不要一次写完整个项目。按照以下顺序逐步完成并运行:
1. 定义初始 Agent 列表;
2. 完成并测试 `print_menu()`
3. 完成并测试 `print_agents()`
4. 完成并测试 `find_agent_by_name()`
5. 完成新增功能;
6. 完成状态修改功能;
7. 完成删除功能;
8. 完成工具查看功能;
9. 最后编写 `main()` 菜单循环;
10. 按验收用例完整测试。
每完成一个函数就运行一次,可以更早发现问题。
## 十、验收测试
### 测试一:查看初始数据
操作:输入 `1`
预期:显示代码助手和聊天助手,状态分别为启用和停用。
### 测试二:新增 Agent
操作:
```text
输入菜单2
名称:搜索助手
模型gpt-5
工具:搜索,网页浏览
```
再次输入 `1`,预期显示三条 Agent 数据。
### 测试三:拒绝重复名称
再次新增“搜索助手”,预期输出“该 Agent 已存在。”,列表数量不增加。
### 测试四:修改状态
输入 `3` 并选择“聊天助手”,预期状态由停用变为启用。
### 测试五:查看工具
输入 `5` 并选择“代码助手”,预期依次显示“搜索”和“终端”。
### 测试六:删除 Agent
输入 `4` 并删除“聊天助手”,再次查看列表时不再显示它。
### 测试七:无效名称
查询、修改或删除一个不存在的名称,程序应显示提示且不崩溃。
### 测试八:无效菜单
输入 `9` 或任意未知内容,预期输出“无效选项,请重新输入。”,随后继续显示菜单。
### 测试九:退出程序
输入 `0`,预期输出“程序已退出。”并正常结束。
## 十一、常见错误
### 11.1 在函数内部重新创建列表
功能函数应修改 `main()` 传入的同一个列表。不要在 `add_agent()` 中重新创建一个无关列表。
### 11.2 查找失败后仍继续操作
如果 Agent 不存在,应使用提前返回结束函数,否则继续读取字典可能产生错误。
### 11.3 把布尔值保存为字符串
启用状态应使用 `True``False`,不要使用字符串 `"True"``"False"`
### 11.4 忘记清理用户输入
名称和工具建议使用 `strip()`,否则多余空格可能导致名称匹配失败。
### 11.5 菜单无法退出
处理选项 `0` 时必须执行 `break`,否则 `while True` 会继续运行。
### 11.6 在导入文件时自动启动程序
示例最后使用:
```python
if __name__ == "__main__":
main()
```
这是程序入口判断。本课先理解为:“直接运行当前文件时才调用 `main()`”。模块与包课程会进一步解释。
## 十二、项目小结
完成本项目后,你已经把前 13 课的知识组合成了一个完整程序:
- 字符串保存名称和模型;
- 布尔值保存启用状态;
- 列表保存多条记录和工具;
- 字典表示单个 Agent
- 集合思想用于理解工具去重;
- 条件判断分发菜单操作;
- 循环维持程序运行并遍历数据;
- 函数拆分不同业务功能;
- 返回值传递查找结果。
## 十三、完成标准
- 所有菜单选项均能正常执行;
- 可以新增、查看、修改和删除 Agent
- 可以查看指定 Agent 的工具;
- 重复名称不会被新增;
- 无效输入不会导致程序崩溃;
- 输入 `0` 可以正常退出;
- 每个函数只承担一个清晰职责;
- 变量名和函数名使用规范英文蛇形命名;
- 代码包含必要的中文注释;
- 九组验收测试全部通过。

View File

@@ -0,0 +1,194 @@
# 第 1-14 课完整示例:命令行 Agent 管理系统
#
# 本项目综合使用变量、字符串、列表、字典、条件判断、循环和函数。
# 建议先运行程序体验功能,再按照讲义中的开发顺序阅读代码。
def print_separator():
"""输出分隔线,让菜单和结果更容易阅读。"""
print("=" * 30)
def print_menu():
"""输出主菜单;本函数只负责显示,不需要返回值。"""
print_separator()
print("命令行 Agent 管理系统")
print("1. 查看全部 Agent")
print("2. 新增 Agent")
print("3. 修改 Agent 状态")
print("4. 删除 Agent")
print("5. 查看 Agent 工具")
print("0. 退出程序")
print_separator()
def get_status_text(enabled):
"""把布尔状态转换成适合显示的中文文本。"""
if enabled:
return "启用"
return "停用"
def print_agents(agents):
"""按照统一格式输出列表中的全部 Agent。"""
if not agents:
print("当前没有 Agent。")
return
print("全部 Agent")
for number, agent in enumerate(agents, start=1):
status_text = get_status_text(agent["enabled"])
print(
f"{number}. {agent['name']}"
f"模型:{agent['model']}"
f"状态:{status_text}"
)
def find_agent_by_name(agents, name):
"""按名称查找 Agent找到时返回字典否则返回 None。"""
for agent in agents:
if agent["name"] == name:
return agent
return None
def parse_tools(tools_text):
"""把英文逗号分隔的文本转换成没有空字符串的工具列表。"""
tools = []
for tool in tools_text.split(","):
clean_tool = tool.strip()
# 只添加非空工具,同时避免同一个工具重复出现。
if clean_tool and clean_tool not in tools:
tools.append(clean_tool)
return tools
def add_agent(agents):
"""接收用户输入,检查名称后新增 Agent。"""
name = input("请输入 Agent 名称:").strip()
if not name:
print("Agent 名称不能为空。")
return
if find_agent_by_name(agents, name) is not None:
print("该 Agent 已存在。")
return
model = input("请输入模型名称:").strip()
tools_text = input("请输入工具,多个工具使用英文逗号分隔:")
tools = parse_tools(tools_text)
new_agent = {
"name": name,
"model": model,
"enabled": True,
"tools": tools,
}
agents.append(new_agent)
print("Agent 新增成功。")
def change_agent_status(agents):
"""查找指定 Agent并反转它的启用状态。"""
name = input("请输入需要修改状态的 Agent 名称:").strip()
agent = find_agent_by_name(agents, name)
if agent is None:
print("未找到该 Agent。")
return
agent["enabled"] = not agent["enabled"]
status_text = get_status_text(agent["enabled"])
print(f"状态修改成功,当前状态:{status_text}")
def delete_agent(agents):
"""查找并删除指定 Agent。"""
name = input("请输入需要删除的 Agent 名称:").strip()
agent = find_agent_by_name(agents, name)
if agent is None:
print("未找到该 Agent。")
return
agents.remove(agent)
print("Agent 已删除。")
def print_agent_tools(agents):
"""输出指定 Agent 的全部工具。"""
name = input("请输入需要查看工具的 Agent 名称:").strip()
agent = find_agent_by_name(agents, name)
if agent is None:
print("未找到该 Agent。")
return
tools = agent.get("tools", [])
if not tools:
print("该 Agent 暂无工具。")
return
print(f"{agent['name']}的工具:")
for number, tool in enumerate(tools, start=1):
print(f"{number}. {tool}")
def create_initial_agents():
"""创建程序启动时使用的初始 Agent 数据。"""
return [
{
"name": "代码助手",
"model": "gpt-5",
"enabled": True,
"tools": ["搜索", "终端"],
},
{
"name": "聊天助手",
"model": "o3",
"enabled": False,
"tools": ["搜索"],
},
]
def main():
"""创建数据并通过循环组织整个菜单流程。"""
agents = create_initial_agents()
while True:
print_menu()
choice = input("请输入菜单编号:").strip()
if choice == "1":
print_agents(agents)
elif choice == "2":
add_agent(agents)
elif choice == "3":
change_agent_status(agents)
elif choice == "4":
delete_agent(agents)
elif choice == "5":
print_agent_tools(agents)
elif choice == "0":
print("程序已退出。")
break
else:
print("无效选项,请重新输入。")
# 只有直接运行当前文件时才启动菜单。
# 后续“模块与包”课程会进一步解释 __name__ 的作用。
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,135 @@
# 第 1-14 课课堂练习:命令行 Agent 管理系统
#
# 这是 Python 基础阶段综合项目,请按照题目顺序逐步完成。
# 完成要求:
# 1. 每完成一个函数就单独调用并测试,不要等全部写完再运行。
# 2. 需要查找结果时使用 return不要依赖全局变量传递结果。
# 3. 函数名和变量名使用有意义的英文蛇形命名。
# 4. 函数体使用四个空格缩进,并添加必要的中文注释。
# 5. 不要删除题目、测试数据、预期结果和自查注释。
# 6. 完成所有功能后,再执行末尾列出的九组验收测试。
# 第一部分:准备初始数据
# 创建列表 agents其中包含以下两个字典
# 1. name="代码助手"、model="gpt-5"、enabled=True、tools=["搜索", "终端"]
# 2. name="聊天助手"、model="o3"、enabled=False、tools=["搜索"]。
# 完成后临时使用 print(agents) 检查结构,确认每个 Agent 都是一个字典。
# 第二部分:定义 print_menu() 函数
# 1. 函数不接收参数,也不需要 return。
# 2. 使用 print() 输出以下菜单:
# 1. 查看全部 Agent
# 2. 新增 Agent
# 3. 修改 Agent 状态
# 4. 删除 Agent
# 5. 查看 Agent 工具
# 0. 退出程序
# 3. 单独调用一次 print_menu(),确认六个选项均正确显示。
# 第三部分:定义 get_status_text(enabled) 函数
# 1. 参数 enabled 接收布尔值。
# 2. enabled 为 True 时 return "启用",否则 return "停用"。
# 3. 分别传入 True 和 False保存并输出返回值。
# 4. 两次预期输出分别为“启用”和“停用”。
# 第四部分:定义 print_agents(agents) 函数
# 1. 参数 agents 接收 Agent 列表,本函数只负责输出,不需要 return。
# 2. 如果列表为空,输出“当前没有 Agent。”并提前结束函数。
# 3. 如果列表非空,使用 enumerate(agents, start=1) 遍历。
# 4. 调用 get_status_text() 得到中文状态。
# 5. 每条记录按照以下格式输出:
# 1. 代码助手模型gpt-5状态启用
# 6. 分别传入初始 agents 和空列表 [] 测试两个分支。
# 第五部分:定义 find_agent_by_name(agents, name) 函数
# 1. 遍历 agents比较 agent["name"] 和参数 name。
# 2. 找到同名 Agent 时,立即 return 对应的 Agent 字典。
# 3. 循环结束仍未找到时return None。
# 4. 查找“代码助手”,预期返回对应字典。
# 5. 查找“不存在的助手”,预期返回 None。
# 注意:本函数只负责查找,不在函数内部输出“找到”或“未找到”。
# 第六部分:定义 parse_tools(tools_text) 函数
# 1. 参数接收英文逗号分隔的工具文本。
# 2. 使用 tools_text.split(",") 拆分字符串。
# 3. 遍历拆分结果,对每个工具调用 strip()。
# 4. 只把非空且尚未存在的工具加入结果列表。
# 5. 使用 "搜索, 终端,搜索, ,计算器" 测试。
# 6. 预期返回 ["搜索", "终端", "计算器"]。
# 第七部分:定义 add_agent(agents) 函数
# 1. 输入 Agent 名称并清理两侧空白。
# 2. 名称为空时输出“Agent 名称不能为空。”并提前 return。
# 3. 调用 find_agent_by_name() 检查名称;重复时输出“该 Agent 已存在。”并 return。
# 4. 输入模型名称。
# 5. 输入英文逗号分隔的工具文本,并调用 parse_tools() 得到工具列表。
# 6. 创建包含 name、model、enabled 和 tools 的字典,新 Agent 默认 enabled=True。
# 7. 使用 agents.append() 添加字典并输出“Agent 新增成功。”。
# 8. 新增“搜索助手”后调用 print_agents(),预期列表共有三条记录。
# 第八部分:定义 change_agent_status(agents) 函数
# 1. 输入 Agent 名称并调用 find_agent_by_name()。
# 2. 未找到时输出“未找到该 Agent。”并提前 return。
# 3. 找到时执行 agent["enabled"] = not agent["enabled"]。
# 4. 调用 get_status_text() 得到修改后的中文状态并输出。
# 5. 修改“聊天助手”后,它的状态应由 False 变为 True。
# 第九部分:定义 delete_agent(agents) 函数
# 1. 输入 Agent 名称并调用 find_agent_by_name()。
# 2. 未找到时输出“未找到该 Agent。”并提前 return。
# 3. 找到时使用 agents.remove(agent) 删除整个字典。
# 4. 输出“Agent 已删除。”。
# 5. 删除“聊天助手”后调用 print_agents(),确认它不再出现。
# 第十部分:定义 print_agent_tools(agents) 函数
# 1. 输入 Agent 名称并调用 find_agent_by_name()。
# 2. 未找到时输出“未找到该 Agent。”并提前 return。
# 3. 使用 agent.get("tools", []) 安全读取工具列表。
# 4. 工具列表为空时输出“该 Agent 暂无工具。”并提前 return。
# 5. 有工具时使用 enumerate(tools, start=1) 遍历并按编号输出。
# 6. 查看“代码助手”时,预期依次显示“搜索”和“终端”。
# 第十一部分:定义 main() 函数
# 1. 在函数内部使用 while True 持续运行菜单。
# 2. 每轮先调用 print_menu(),再用 input() 接收菜单编号并调用 strip()。
# 3. 使用 if...elif...else 完成以下分发:
# "1" 调用 print_agents(agents)
# "2" 调用 add_agent(agents)
# "3" 调用 change_agent_status(agents)
# "4" 调用 delete_agent(agents)
# "5" 调用 print_agent_tools(agents)
# "0" 输出“程序已退出。”并使用 break 结束循环;
# 其他内容输出“无效选项,请重新输入。”。
# 4. 在文件最后调用 main(),启动完整程序。
# 最终验收测试:
# 1. 输入 1确认显示两个初始 Agent
# 2. 输入 2新增“搜索助手”再次查看时共有三条记录
# 3. 再次新增“搜索助手”,确认重复名称被拒绝;
# 4. 输入 3把“聊天助手”从停用修改为启用
# 5. 输入 5确认“代码助手”显示两个工具
# 6. 输入 4删除“聊天助手”确认列表中不再显示它
# 7. 使用不存在的名称进行查询、修改或删除,确认程序不崩溃;
# 8. 输入 9确认显示无效选项后菜单继续运行
# 9. 输入 0确认程序正常退出。
# 完成后进行代码自查:
# 1. 是否使用列表保存多个 Agent
# 2. 每个 Agent 是否使用字典表示;
# 3. enabled 是否使用真正的布尔值;
# 4. find_agent_by_name() 是否返回字典或 None
# 5. 查找失败后是否提前 return
# 6. 是否使用函数拆分不同功能;
# 7. 菜单循环是否能够正常退出;
# 8. 重复名称是否不会被添加;
# 9. 工具文本是否完成拆分、清理和去重;
# 10. 九组验收测试是否全部通过。