From 691405f3801786013a34f5939d86429710aae2c2 Mon Sep 17 00:00:00 2001 From: bruce Date: Mon, 3 Aug 2026 21:26:53 +0800 Subject: [PATCH] =?UTF-8?q?feat(python=E8=BF=9B=E9=98=B6):=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E6=A8=A1=E5=9D=97=E4=B8=8E=E5=8C=85=E8=AF=BE=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 02_python进阶/2_1_模块与包/README.md | 402 ++++++++++++++++++ .../2_1_模块与包/agent_package/__init__.py | 4 + .../2_1_模块与包/agent_package/status_text.py | 9 + 02_python进阶/2_1_模块与包/agent_tools.py | 29 ++ 02_python进阶/2_1_模块与包/module_example.py | 63 +++ 02_python进阶/2_1_模块与包/practice.py | 46 ++ README.md | 16 +- 7 files changed, 562 insertions(+), 7 deletions(-) create mode 100644 02_python进阶/2_1_模块与包/README.md create mode 100644 02_python进阶/2_1_模块与包/agent_package/__init__.py create mode 100644 02_python进阶/2_1_模块与包/agent_package/status_text.py create mode 100644 02_python进阶/2_1_模块与包/agent_tools.py create mode 100644 02_python进阶/2_1_模块与包/module_example.py create mode 100644 02_python进阶/2_1_模块与包/practice.py diff --git a/02_python进阶/2_1_模块与包/README.md b/02_python进阶/2_1_模块与包/README.md new file mode 100644 index 0000000..a4a1830 --- /dev/null +++ b/02_python进阶/2_1_模块与包/README.md @@ -0,0 +1,402 @@ +# 第 2-1 课:模块与包 + +## 一、本课目标 + +完成本课后,你将能够: + +1. 说出模块和包分别是什么; +2. 解释为什么要把较长的程序拆分成多个文件; +3. 使用 `import` 导入模块; +4. 使用 `from...import...` 导入指定内容; +5. 创建并使用自己的模块和包; +6. 理解 `if __name__ == "__main__":` 的基本作用。 + +## 二、前置知识 + +学习本课前,需要掌握: + +- 变量和基本数据类型; +- 列表与字典; +- 条件判断与循环; +- 函数、参数和返回值; +- 知道 Python 代码保存在 `.py` 文件中。 + +本课是 Python 进阶阶段的第一课,但不会使用复杂语法。 + +## 三、模块是什么 + +模块(Module)通常就是一个保存了 Python 代码的 `.py` 文件。 + +前面的课程大多把函数和主程序写在同一个文件中。程序越来越大后,这种方式会产生三个问题: + +1. 文件太长,不容易阅读; +2. 不同功能混在一起,不容易修改; +3. 已经写好的函数不方便在其他程序中重复使用。 + +把相关函数放进单独文件,可以让代码职责更清晰。例如: + +```text +agent_tools.py 保存 Agent 工具相关函数 +module_example.py 组织程序运行流程 +``` + +`agent_tools.py` 就是一个自定义模块。 + +## 四、使用 `import` 导入模块 + +导入(Import)表示让当前文件能够使用另一个模块中的内容。 + +### 4.1 导入标准库模块 + +标准库(Standard Library)是安装 Python 时自带的一组模块,不需要另外下载。本课使用 `random` 模块随机选择列表元素: + +```python +import random + +tools = ["搜索", "终端", "计算器"] +recommended_tool = random.choice(tools) +print(recommended_tool) +``` + +这里: + +- `import random` 导入整个模块; +- `random.choice()` 表示调用 `random` 模块中的 `choice()` 函数; +- 函数会从列表中随机选择一个元素,因此每次结果可能不同。 + +### 4.2 导入自己的模块 + +课程目录中的 `agent_tools.py` 定义了函数和变量。在同一目录的 `module_example.py` 中可以这样使用: + +```python +import agent_tools + +tool_count = agent_tools.get_tool_count(agent_tools.DEFAULT_TOOLS) +print(tool_count) +``` + +导入时不写 `.py`,因此使用的是 `import agent_tools`,不是 `import agent_tools.py`。 + +通过 `模块名.名称` 可以清楚看出这个变量或函数来自哪里。 + +## 五、使用 `from...import...` + +如果当前文件只需要模块中的少量内容,可以导入指定名称: + +```python +from agent_tools import build_agent_description + +description = build_agent_description("代码助手", "gpt-5") +print(description) +``` + +导入后可以直接写函数名,不再需要添加 `agent_tools.`。 + +两种写法都正确: + +```python +import agent_tools +agent_tools.build_agent_description("代码助手", "gpt-5") +``` + +```python +from agent_tools import build_agent_description +build_agent_description("代码助手", "gpt-5") +``` + +入门阶段建议优先使用清晰、容易看出来源的写法。不要使用 `from agent_tools import *`,因为星号会一次导入许多名称,容易造成重名和阅读困难。 + +## 六、导入模块时会发生什么 + +第一次导入模块时,Python 会从上到下执行模块中的代码。函数定义只是创建函数,不会自动调用函数;但直接写在文件最外层的 `print()` 会立即执行。 + +为了区分“直接运行文件”和“把文件作为模块导入”,可以使用: + +```python +if __name__ == "__main__": + main() +``` + +`__name__` 是 Python 自动提供的特殊变量: + +- 直接运行当前文件时,`__name__` 的值是 `"__main__"`; +- 当前文件被其他文件导入时,`__name__` 的值是模块名。 + +因此,可以把模块的测试代码放进 `main()`,再通过入口判断调用: + +```python +def main(): + print("正在测试模块。") + + +if __name__ == "__main__": + main() +``` + +这样直接运行模块时会执行测试,导入模块时不会意外输出测试文字。 + +## 七、包是什么 + +包(Package)是用于组织多个模块的文件夹。 + +本课示例结构如下: + +```text +agent_package/ +├── __init__.py +└── status_text.py +``` + +`__init__.py` 用来明确表示这个目录是一个 Python 包。本课暂时不在其中编写功能,只保留说明注释。 + +从包中的模块导入函数: + +```python +from agent_package.status_text import get_status_text + +status_text = get_status_text(True) +print(status_text) +``` + +可以把导入路径从左到右理解为: + +```text +agent_package 包 → status_text 模块 → get_status_text 函数 +``` + +## 八、示例文件 + +本课包含以下示例: + +```text +02_python进阶/2_1_模块与包/ +├── README.md +├── module_example.py +├── agent_tools.py +├── practice.py +└── agent_package/ + ├── __init__.py + └── status_text.py +``` + +- `module_example.py`:完整主程序; +- `agent_tools.py`:自己编写的模块; +- `agent_package/`:自己编写的简单包; +- `practice.py`:课堂练习。 + +## 九、运行方法 + +打开 PowerShell,进入项目根目录: + +```powershell +cd F:\PyCharm\PythonLearn +``` + +运行完整示例: + +```powershell +python .\02_python进阶\2_1_模块与包\module_example.py +``` + +直接运行自定义模块的测试: + +```powershell +python .\02_python进阶\2_1_模块与包\agent_tools.py +``` + +完成练习后运行: + +```powershell +python .\02_python进阶\2_1_模块与包\practice.py +``` + +## 十、运行结果 + +运行 `module_example.py` 时,会看到类似结果: + +```text +一、标准库模块 +随机推荐工具:搜索 +============================== +二、自定义模块 +默认工具:['搜索', '终端'] +默认工具数量:2 +代码助手 使用 gpt-5 模型 +============================== +三、自定义包 +Agent 状态:启用 +``` + +第一部分使用了随机选择,因此也可能显示“终端”或“计算器”,这不是错误。 + +运行 `agent_tools.py` 时,预期看到: + +```text +正在测试 agent_tools 模块。 +默认工具数量:2 +``` + +## 十一、关键代码执行顺序 + +运行 `module_example.py` 时,Python 大致按照以下顺序工作: + +1. 执行文件顶部的导入语句; +2. 找到并加载标准库模块 `random`; +3. 找到同一目录中的 `agent_tools.py`; +4. 找到 `agent_package` 包中的 `status_text.py`; +5. 创建当前文件中定义的函数; +6. 执行文件末尾的程序入口判断; +7. 因为当前文件是直接运行的,所以调用 `main()`; +8. `main()` 依次调用三个演示函数并输出结果。 + +导入 `agent_tools.py` 时,它的入口判断不成立,所以不会自动执行 `show_module_test()`。 + +## 十二、常见错误 + +### 12.1 导入时写了 `.py` + +错误写法: + +```python +import agent_tools.py +``` + +正确写法: + +```python +import agent_tools +``` + +模块名不包含文件扩展名 `.py`。 + +### 12.2 文件名与导入名不一致 + +如果文件名是 `agent_tools.py`,就应使用 `import agent_tools`。少写字母或使用不同名称,会出现: + +```text +ModuleNotFoundError: No module named 'agent_tool' +``` + +中文解释:Python 没有找到名为 `agent_tool` 的模块。请检查文件名、导入名和运行目录。 + +### 12.3 导入整个模块后直接调用函数 + +如果使用: + +```python +import agent_tools +``` + +就要通过模块名调用: + +```python +agent_tools.get_tool_count([]) +``` + +直接写 `get_tool_count([])` 会出现名称未定义错误。 + +### 12.4 自定义模块名与标准库重名 + +不要把自己的文件命名为 `random.py`,否则 `import random` 可能导入自己的文件,而不是 Python 标准库模块。 + +### 12.5 导入模块时出现意外输出 + +如果测试用的 `print()` 直接写在模块最外层,导入模块时也会执行。把测试代码放进 `main()`,再使用程序入口判断。 + +### 12.6 包或模块不在预期位置 + +本课请保持示例目录结构不变,并从项目根目录执行讲义中的命令。目录位置错误会导致 Python 找不到需要导入的内容。 + +## 十三、课堂练习 + +打开 `practice.py`,按照注释依次完成五部分: + +1. 创建 `calculator.py` 模块; +2. 分别使用两种方式导入加法函数; +3. 为模块添加安全的测试入口; +4. 创建 `text_package` 包; +5. 从包中的模块导入文本处理函数。 + +建议先独立完成。如果遇到困难,先检查文件名、目录位置和导入语句是否一致。 + +## 十四、参考答案 + +请先独立练习,再展开查看。 + +
+查看参考答案 + +`calculator.py`: + +```python +def add(first, second): + """返回两个数字相加的结果。""" + return first + second + + +def main(): + """测试当前模块的加法功能。""" + print("正在测试计算模块。") + + +if __name__ == "__main__": + main() +``` + +`text_package/__init__.py`: + +```python +# 这个文件表示 text_package 是一个 Python 包。 +``` + +`text_package/text_tools.py`: + +```python +def make_title(text): + """为文本添加标题装饰。""" + return f"=== {text} ===" +``` + +`practice.py` 中需要补充的核心代码: + +```python +import calculator +from calculator import add +from text_package.text_tools import make_title + + +result = calculator.add(10, 20) +print(f"计算结果:{result}") + +new_result = add(5, 8) +print(f"新的计算结果:{new_result}") + +title = make_title("Python 学习") +print(title) +``` + +
+ +## 十五、本课小结 + +- 模块通常是一个 `.py` 文件; +- 模块可以拆分功能,并让代码在多个程序中重复使用; +- `import 模块名` 会导入整个模块; +- `from 模块名 import 名称` 会导入指定内容; +- `if __name__ == "__main__":` 可以避免导入模块时自动执行测试或主程序; +- 包是用于组织多个模块的文件夹; +- 可以使用点号表示“包、模块、名称”之间的层级关系。 + +## 十六、验收标准 + +完成本课时,应满足以下条件: + +- 可以成功运行 `module_example.py`; +- 可以解释模块与包的区别; +- 可以使用两种方式导入模块内容; +- 可以创建并导入自己的 `.py` 模块; +- 可以解释入口判断的基本作用; +- 可以创建包含 `__init__.py` 的简单包; +- 可以完成 `practice.py` 中的五部分练习; +- 运行练习时得到 `30`、`13` 和 `=== Python 学习 ===`; +- 导入 `calculator` 时不会自动输出模块测试文字。 diff --git a/02_python进阶/2_1_模块与包/agent_package/__init__.py b/02_python进阶/2_1_模块与包/agent_package/__init__.py new file mode 100644 index 0000000..1bb9639 --- /dev/null +++ b/02_python进阶/2_1_模块与包/agent_package/__init__.py @@ -0,0 +1,4 @@ +# 这个文件表示 agent_package 是一个 Python 包。 +# +# 包就是用于组织多个模块的文件夹。 +# 目前先保留简单注释,后续课程会继续学习更复杂的包结构。 diff --git a/02_python进阶/2_1_模块与包/agent_package/status_text.py b/02_python进阶/2_1_模块与包/agent_package/status_text.py new file mode 100644 index 0000000..aeb1d86 --- /dev/null +++ b/02_python进阶/2_1_模块与包/agent_package/status_text.py @@ -0,0 +1,9 @@ +# 第 2-1 课示例:包中的模块 + + +def get_status_text(enabled): + """把布尔值状态转换成中文文本。""" + if enabled: + return "启用" + + return "停用" diff --git a/02_python进阶/2_1_模块与包/agent_tools.py b/02_python进阶/2_1_模块与包/agent_tools.py new file mode 100644 index 0000000..2c75628 --- /dev/null +++ b/02_python进阶/2_1_模块与包/agent_tools.py @@ -0,0 +1,29 @@ +# 第 2-1 课示例:自定义模块 +# +# 模块就是一个 Python 文件。 +# 这个文件集中保存与 Agent 工具有关的函数,供其他文件导入使用。 + + +DEFAULT_TOOLS = ["搜索", "终端"] + + +def get_tool_count(tools): + """返回工具列表中的工具数量。""" + return len(tools) + + +def build_agent_description(name, model): + """根据名称和模型生成 Agent 描述。""" + return f"{name} 使用 {model} 模型" + + +def show_module_test(): + """输出本模块的测试结果。""" + print("正在测试 agent_tools 模块。") + print(f"默认工具数量:{get_tool_count(DEFAULT_TOOLS)}") + + +# 只有直接运行本文件时,才执行下面的测试代码。 +# 其他文件导入本模块时,不会自动执行测试。 +if __name__ == "__main__": + show_module_test() diff --git a/02_python进阶/2_1_模块与包/module_example.py b/02_python进阶/2_1_模块与包/module_example.py new file mode 100644 index 0000000..5893af2 --- /dev/null +++ b/02_python进阶/2_1_模块与包/module_example.py @@ -0,0 +1,63 @@ +# 第 2-1 课完整示例:模块与包 +# +# 本文件依次演示: +# 1. 使用 import 导入 Python 标准库模块; +# 2. 使用 import 导入自己编写的模块; +# 3. 使用 from...import... 导入指定内容; +# 4. 从自定义包中导入模块; +# 5. 使用程序入口判断组织主程序。 + +import random + +import agent_tools +from agent_tools import build_agent_description +from agent_package.status_text import get_status_text + + +def print_separator(): + """输出分隔线,让不同示例更容易阅读。""" + print("=" * 30) + + +def show_standard_library_example(): + """演示使用标准库模块生成随机推荐。""" + tools = ["搜索", "终端", "计算器"] + recommended_tool = random.choice(tools) + print(f"随机推荐工具:{recommended_tool}") + + +def show_custom_module_example(): + """演示使用自己编写的 agent_tools 模块。""" + tool_count = agent_tools.get_tool_count(agent_tools.DEFAULT_TOOLS) + print(f"默认工具:{agent_tools.DEFAULT_TOOLS}") + print(f"默认工具数量:{tool_count}") + + description = build_agent_description("代码助手", "gpt-5") + print(description) + + +def show_package_example(): + """演示从自定义包中导入并使用函数。""" + enabled = True + status_text = get_status_text(enabled) + print(f"Agent 状态:{status_text}") + + +def main(): + """按照顺序运行本课的三个示例。""" + print("一、标准库模块") + show_standard_library_example() + + print_separator() + + print("二、自定义模块") + show_custom_module_example() + + print_separator() + + print("三、自定义包") + show_package_example() + + +if __name__ == "__main__": + main() diff --git a/02_python进阶/2_1_模块与包/practice.py b/02_python进阶/2_1_模块与包/practice.py new file mode 100644 index 0000000..a21d582 --- /dev/null +++ b/02_python进阶/2_1_模块与包/practice.py @@ -0,0 +1,46 @@ +# 第 2-1 课课堂练习:模块与包 +# +# 请先完成讲义中的学习和示例运行,再按照顺序完成练习。 +# 不要删除题目和预期结果;每完成一部分就运行一次。 + + + +# 第一部分:创建自定义模块 +# 1. 在当前课程目录创建 calculator.py。 +# 2. 在 calculator.py 中定义 add(first, second) 函数。 +# 3. 函数返回两个数字相加的结果。 + + + +# 第二部分:使用 import 导入模块 +# 1. 在本文件中使用 import calculator 导入模块。 +# 2. 调用 calculator.add(10, 20)。 +# 3. 输出格式为“计算结果:30”。 + +# 第三部分:使用 from...import... 导入函数 +# 1. 使用 from calculator import add 导入 add()。 +# 2. 直接调用 add(5, 8)。 +# 3. 输出格式为“新的计算结果:13”。 +# 第四部分:理解程序入口 +# 1. 在 calculator.py 中定义 main() 函数。 +# 2. main() 输出“正在测试计算模块。”。 +# 3. 使用 if __name__ == "__main__": 判断后调用 main()。 +# 4. 直接运行 calculator.py 时,应看到测试文字。 +# 5. 运行 practice.py 时,不应自动看到测试文字。 + + +# 第五部分:创建自己的包 +# 1. 在当前课程目录创建 text_package 文件夹。 +# 2. 在其中创建 __init__.py 和 text_tools.py。 +# 3. 在 text_tools.py 中定义 make_title(text) 函数。 +# 4. 函数返回 f"=== {text} ==="。 +# 5. 在本文件中从 text_package.text_tools 导入 make_title。 +# 6. 调用函数并输出,预期结果为“=== Python 学习 ===”。 + +# 完成后自查: +# 1. 是否理解一个 .py 文件可以作为模块; +# 2. 是否会使用 import 模块名; +# 3. 是否会使用 from 模块名 import 名称; +# 4. 是否知道导入模块时不会执行入口判断中的测试代码; +# 5. 是否能创建包含 __init__.py 的简单包; +# 6. 是否能从包中的模块导入函数。 diff --git a/README.md b/README.md index 97ff3c0..9b8e0d3 100644 --- a/README.md +++ b/README.md @@ -188,13 +188,13 @@ Python/ ## 当前学习进度 -- 当前阶段:第一阶段——Python 基础语法。 -- 当前课程:`1_14_python基础综合项目`。 -- 当前状态:第一阶段 Python 基础课程已完成。 +- 当前阶段:第二阶段——Python 进阶。 +- 当前课程:`2_1_模块与包`。 +- 当前状态:正在学习模块与包。 - 已完成课程:`1_1_hello_world` 至 `1_14_python基础综合项目`。 -- 学习中的课程:暂无。 -- 已创建课程目录:`01_python基础/1_1_hello_world/` 至 `01_python基础/1_14_python基础综合项目/`。 -- 下一步:进入第二阶段 Python 进阶,学习模块与包。 +- 学习中的课程:`2_1_模块与包`。 +- 已创建课程目录:第一阶段全部课程,以及 `02_python进阶/2_1_模块与包/`。 +- 下一步:完成模块与包练习,然后学习文件和目录操作。 ## 建议环境 @@ -209,10 +209,12 @@ Python/ ## 下一步 -第一阶段 Python 基础课程已经完成。下一课将学习: +当前正在学习模块与包。本课将学习: 1. 模块是什么,以及为什么要拆分文件; 2. 使用 `import` 导入模块; 3. 使用 `from...import...` 导入指定内容; 4. 理解 `__name__ == "__main__"`; 5. 创建和使用自己的模块与包。 + +完成本课练习并确认继续后,下一课将学习文件和目录操作。