Files
PythonLearn/02_python进阶/2_1_模块与包

第 2-1 课:模块与包

一、本课目标

完成本课后,你将能够:

  1. 说出模块和包分别是什么;
  2. 解释为什么要把较长的程序拆分成多个文件;
  3. 使用 import 导入模块;
  4. 使用 from...import... 导入指定内容;
  5. 创建并使用自己的模块和包;
  6. 理解 if __name__ == "__main__": 的基本作用。

二、前置知识

学习本课前,需要掌握:

  • 变量和基本数据类型;
  • 列表与字典;
  • 条件判断与循环;
  • 函数、参数和返回值;
  • 知道 Python 代码保存在 .py 文件中。

本课是 Python 进阶阶段的第一课,但不会使用复杂语法。

三、模块是什么

模块Module通常就是一个保存了 Python 代码的 .py 文件。

前面的课程大多把函数和主程序写在同一个文件中。程序越来越大后,这种方式会产生三个问题:

  1. 文件太长,不容易阅读;
  2. 不同功能混在一起,不容易修改;
  3. 已经写好的函数不方便在其他程序中重复使用。

把相关函数放进单独文件,可以让代码职责更清晰。例如:

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.pyPython 大致按照以下顺序工作:

  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

错误写法:

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,按照注释依次完成五部分:

  1. 创建 calculator.py 模块;
  2. 分别使用两种方式导入加法函数;
  3. 为模块添加安全的测试入口;
  4. 创建 text_package 包;
  5. 从包中的模块导入文本处理函数。

建议先独立完成。如果遇到困难,先检查文件名、目录位置和导入语句是否一致。

十四、参考答案

请先独立练习,再展开查看。

查看参考答案

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 中的五部分练习;
  • 运行练习时得到 3013=== Python 学习 ===
  • 导入 calculator 时不会自动输出模块测试文字。