第 2-1 课:模块与包
一、本课目标
完成本课后,你将能够:
- 说出模块和包分别是什么;
- 解释为什么要把较长的程序拆分成多个文件;
- 使用
import导入模块; - 使用
from...import...导入指定内容; - 创建并使用自己的模块和包;
- 理解
if __name__ == "__main__":的基本作用。
二、前置知识
学习本课前,需要掌握:
- 变量和基本数据类型;
- 列表与字典;
- 条件判断与循环;
- 函数、参数和返回值;
- 知道 Python 代码保存在
.py文件中。
本课是 Python 进阶阶段的第一课,但不会使用复杂语法。
三、模块是什么
模块(Module)通常就是一个保存了 Python 代码的 .py 文件。
前面的课程大多把函数和主程序写在同一个文件中。程序越来越大后,这种方式会产生三个问题:
- 文件太长,不容易阅读;
- 不同功能混在一起,不容易修改;
- 已经写好的函数不方便在其他程序中重复使用。
把相关函数放进单独文件,可以让代码职责更清晰。例如:
agent_tools.py 保存 Agent 工具相关函数
module_example.py 组织程序运行流程
agent_tools.py 就是一个自定义模块。
四、使用 import 导入模块
导入(Import)表示让当前文件能够使用另一个模块中的内容。
4.1 导入标准库模块
标准库(Standard Library)是安装 Python 时自带的一组模块,不需要另外下载。本课使用 random 模块随机选择列表元素:
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 中可以这样使用:
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...
如果当前文件只需要模块中的少量内容,可以导入指定名称:
from agent_tools import build_agent_description
description = build_agent_description("代码助手", "gpt-5")
print(description)
导入后可以直接写函数名,不再需要添加 agent_tools.。
两种写法都正确:
import agent_tools
agent_tools.build_agent_description("代码助手", "gpt-5")
from agent_tools import build_agent_description
build_agent_description("代码助手", "gpt-5")
入门阶段建议优先使用清晰、容易看出来源的写法。不要使用 from agent_tools import *,因为星号会一次导入许多名称,容易造成重名和阅读困难。
六、导入模块时会发生什么
第一次导入模块时,Python 会从上到下执行模块中的代码。函数定义只是创建函数,不会自动调用函数;但直接写在文件最外层的 print() 会立即执行。
为了区分“直接运行文件”和“把文件作为模块导入”,可以使用:
if __name__ == "__main__":
main()
__name__ 是 Python 自动提供的特殊变量:
- 直接运行当前文件时,
__name__的值是"__main__"; - 当前文件被其他文件导入时,
__name__的值是模块名。
因此,可以把模块的测试代码放进 main(),再通过入口判断调用:
def main():
print("正在测试模块。")
if __name__ == "__main__":
main()
这样直接运行模块时会执行测试,导入模块时不会意外输出测试文字。
七、包是什么
包(Package)是用于组织多个模块的文件夹。
本课示例结构如下:
agent_package/
├── __init__.py
└── status_text.py
__init__.py 用来明确表示这个目录是一个 Python 包。本课暂时不在其中编写功能,只保留说明注释。
从包中的模块导入函数:
from agent_package.status_text import get_status_text
status_text = get_status_text(True)
print(status_text)
可以把导入路径从左到右理解为:
agent_package 包 → status_text 模块 → get_status_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,进入项目根目录:
cd F:\PyCharm\PythonLearn
运行完整示例:
python .\02_python进阶\2_1_模块与包\module_example.py
直接运行自定义模块的测试:
python .\02_python进阶\2_1_模块与包\agent_tools.py
完成练习后运行:
python .\02_python进阶\2_1_模块与包\practice.py
十、运行结果
运行 module_example.py 时,会看到类似结果:
一、标准库模块
随机推荐工具:搜索
==============================
二、自定义模块
默认工具:['搜索', '终端']
默认工具数量:2
代码助手 使用 gpt-5 模型
==============================
三、自定义包
Agent 状态:启用
第一部分使用了随机选择,因此也可能显示“终端”或“计算器”,这不是错误。
运行 agent_tools.py 时,预期看到:
正在测试 agent_tools 模块。
默认工具数量:2
十一、关键代码执行顺序
运行 module_example.py 时,Python 大致按照以下顺序工作:
- 执行文件顶部的导入语句;
- 找到并加载标准库模块
random; - 找到同一目录中的
agent_tools.py; - 找到
agent_package包中的status_text.py; - 创建当前文件中定义的函数;
- 执行文件末尾的程序入口判断;
- 因为当前文件是直接运行的,所以调用
main(); main()依次调用三个演示函数并输出结果。
导入 agent_tools.py 时,它的入口判断不成立,所以不会自动执行 show_module_test()。
十二、常见错误
12.1 导入时写了 .py
错误写法:
import agent_tools.py
正确写法:
import agent_tools
模块名不包含文件扩展名 .py。
12.2 文件名与导入名不一致
如果文件名是 agent_tools.py,就应使用 import agent_tools。少写字母或使用不同名称,会出现:
ModuleNotFoundError: No module named 'agent_tool'
中文解释:Python 没有找到名为 agent_tool 的模块。请检查文件名、导入名和运行目录。
12.3 导入整个模块后直接调用函数
如果使用:
import agent_tools
就要通过模块名调用:
agent_tools.get_tool_count([])
直接写 get_tool_count([]) 会出现名称未定义错误。
12.4 自定义模块名与标准库重名
不要把自己的文件命名为 random.py,否则 import random 可能导入自己的文件,而不是 Python 标准库模块。
12.5 导入模块时出现意外输出
如果测试用的 print() 直接写在模块最外层,导入模块时也会执行。把测试代码放进 main(),再使用程序入口判断。
12.6 包或模块不在预期位置
本课请保持示例目录结构不变,并从项目根目录执行讲义中的命令。目录位置错误会导致 Python 找不到需要导入的内容。
十三、课堂练习
打开 practice.py,按照注释依次完成五部分:
- 创建
calculator.py模块; - 分别使用两种方式导入加法函数;
- 为模块添加安全的测试入口;
- 创建
text_package包; - 从包中的模块导入文本处理函数。
建议先独立完成。如果遇到困难,先检查文件名、目录位置和导入语句是否一致。
十四、参考答案
请先独立练习,再展开查看。
查看参考答案
calculator.py:
def add(first, second):
"""返回两个数字相加的结果。"""
return first + second
def main():
"""测试当前模块的加法功能。"""
print("正在测试计算模块。")
if __name__ == "__main__":
main()
text_package/__init__.py:
# 这个文件表示 text_package 是一个 Python 包。
text_package/text_tools.py:
def make_title(text):
"""为文本添加标题装饰。"""
return f"=== {text} ==="
practice.py 中需要补充的核心代码:
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时不会自动输出模块测试文字。