Python 模块(Module)与包(Package)
Python 的模块和包是代码组织与复用的核心机制:
- 模块(Module):单个
.py文件,封装变量、函数、类等,是代码复用的最小单元;模块是python程序的基本组织单位。 - 包(Package):包含
__init__.py文件的目录,用于组织多个相关模块,实现代码的分层管理。
一、模块(Module)
1. 如何使用模块?(核心操作:导入)
使用模块的核心是import语句,有 5 种常见导入方式,我会逐个讲清楚:
语法:import 模块名(导入整个模块)
语法:import 模块名 as 别名
语法:from 模块名 import 函数名/变量名/类名 (从模块中导入指定的部分)
语法:from 模块名 import 名称 as 别名
语法:from 模块名 import * (不推荐)
2. 模块的「内置属性」
每个模块都有一些内置的特殊属性,帮你了解模块的信息:
| 内置属性 | 核心含义 | 新手常用场景 / 示例 |
|---|---|---|
__name__ |
作用:获取模块的名字。
|
模块自测(最核心用法 if __name__ == "__main__": |
__file__ |
返回模块文件的完整路径(绝对路径 / 相对路径,取决于系统) | 查看模块位置 |
# 在main.py中执行
import calculator
# __name__:模块的名字
print(calculator.__name__) # 输出:calculator
# __file__:模块的完整路径(告诉你模块文件存在哪里)
print(calculator.__file__) # 输出:你的路径/calculator.py
# __doc__:模块的文档注释(如果模块开头写了"""注释""")
print(calculator.__doc__) # 如果calculator.py开头有文档注释,会输出
3. 模块的「执行逻辑」(重点:if __name__ == "__main__")
现象:当你直接运行模块文件(比如python calculator.py),模块里的所有代码都会执行;但当你把模块导入到其他文件时,模块里的「可执行代码」也会被执行(这通常不是你想要的)。
解决方法:if __name__ == "__main__"
这个判断的作用:只有直接运行当前模块文件时,里面的代码才会执行;导入时不执行。
# calculator.py
PI = 3.1415926
def add(a, b):
return a + b
# 可执行代码(没有这个判断的话,导入时会打印)
print("我是calculator模块里的打印语句")
# 加上判断:只有直接运行calculator.py时,下面的代码才执行
if __name__ == "__main__":
# 可以在这里写模块的测试代码
print("直接运行calculator模块,执行测试")
print("add(2,3)=", add(2, 3))
测试效果:
- 直接运行:
python calculator.py输出:我是calculator模块里的打印语句 直接运行calculator模块,执行测试 add(2,3)= 5 - 在 main.py 中导入 calculator 模块:输出:
✅ 而我是calculator模块里的打印语句 # 这行还是会执行(因为在判断外)if __name__ == "__main__"里的代码不会执行!
最佳实践:模块里的「测试代码」「示例代码」都放在
if __name__ == "__main__"里。
4. 内置模块 vs 自定义模块 vs 第三方模块
| 类型 | 示例 | 获取方式 |
|---|---|---|
| 内置模块 | json、os、sys |
Python 自带,无需安装直接导入即可 本质:Python 官方提前写好的、编译进解释器的 “功能文件”(大部分是 .py,核心模块是 C 实现) |
| 自定义模块 | json_utils.py |
自己写的 本质:你自己写的 .py 文件 |
| 第三方模块 | pandas、requests |
需用 本质:开发者写好的 .py 文件,通过 pip 安装到你的 Python 环境里 |
二、包(Package):模块的「文件夹」
1. 包是什么?
包是:一个包含__init__.py文件的文件夹,这个文件夹里可以放:
- 多个模块文件(
.py) - 子文件夹(子包,同样需要
__init__.py)
简单说:模块是「文件」,包是「装文件的文件夹」(必须有__init__.py)。
2. 包的结构示例
假设你要做一个「学生管理系统」,包的结构可以这样设计:
student_system/ # 根包(文件夹)
├── __init__.py # 包的初始化文件(必须有)
├── basic_info.py # 模块:处理学生基本信息(姓名、年龄)
├── score.py # 模块:处理学生成绩(总分、平均分)
└── utils/ # 子包:工具类
├── __init__.py # 子包的初始化文件(必须有)
└── common.py # 模块:通用功能(比如数据验证)
3. 如何创建包?
步骤 1:创建文件夹(包名)
比如创建student_system文件夹。
步骤 2:在文件夹里创建__init__.py文件
这个文件可以是空的(新手先这么做),也可以写包的初始化代码。
步骤 3:在文件夹里添加模块文件
比如basic_info.py、score.py,以及子包utils(同样要__init__.py)。
4. 如何使用包中的模块?(导入方式)
还是用上面的student_system包举例,先写模块内容:
第一步:编写模块代码
# student_system/basic_info.py
def get_student_name(student_id):
"""根据学号获取姓名"""
student_dict = {"001": "张三", "002": "李四"}
return student_dict.get(student_id, "未知")
# student_system/score.py
def calculate_average(scores):
"""计算平均分"""
if not scores:
return 0
return sum(scores) / len(scores)
# student_system/utils/common.py
def validate_student_id(student_id):
"""验证学号是否合法(必须是3位数字)"""
return len(student_id) == 3 and student_id.isdigit()
第二步:导入包中的模块(4 种常见方式)
假设你在student_system文件夹外,创建一个main.py来调用:
方式 1:导入包中的模块(完整路径)
# main.py
# 导入student_system包中的basic_info模块
import student_system.basic_info as basic_info
# 调用模块中的函数
name = basic_info.get_student_name("001")
print("学生姓名:", name) # 输出:学生姓名:张三
方式 2:从包中直接导入模块
# main.py
# 从student_system包中导入score模块
from student_system import score
# 调用函数
avg = score.calculate_average([85, 90, 95])
print("平均分:", avg) # 输出:平均分:90.0
方式 3:从包的模块中导入指定函数
# main.py
# 从子包的模块中导入函数
from student_system.utils.common import validate_student_id
# 调用函数
print(validate_student_id("001")) # 输出:True
print(validate_student_id("12")) # 输出:False
方式 4:通过__init__.py简化导入(进阶)
如果觉得from student_system.utils.common import validate_student_id太长,可以修改__init__.py来简化:
- 修改
student_system/utils/__init__.py:
# student_system/utils/__init__.py
# 把common模块的validate_student_id导入到utils包的命名空间
from .common import validate_student_id
- 修改
student_system/__init__.py:
# student_system/__init__.py
# 把utils包的validate_student_id导入到根包的命名空间
from .utils import validate_student_id
# 同时导入basic_info的函数
from .basic_info import get_student_name
- 现在
main.py可以这样导入(更简洁):
# main.py
from student_system import get_student_name, validate_student_id
print(get_student_name("002")) # 输出:李四
print(validate_student_id("003")) # 输出:True
5. __init__.py的核心作用
- 标识文件夹是 Python 包:没有这个文件,Python 会把文件夹当成普通文件夹,无法导入其中的模块。
- 初始化包的命名空间:可以在里面导入模块 / 函数,简化外部调用(上面的例子就是)。
- 定义包的
__all__属性(控制from 包 import *的导入内容):比如在student_system/__init__.py中写:# 当执行from student_system import *时,只导入这两个函数 __all__ = ["get_student_name", "validate_student_id"]
三、模块的搜索路径(解决「导入失败」问题)
新手最常遇到的错误:ModuleNotFoundError: No module named 'xxx'—— 本质是 Python 找不到你的模块 / 包。
1. Python 查找模块的顺序
- 当前执行脚本的目录(你运行
python main.py时,main.py 所在的目录) - Python 的内置模块目录(比如
/usr/lib/python3.10/,不用管) - 第三方库安装目录(比如
site-packages,pip 安装的库都在这里) sys.path列表中的其他路径。
2. 查看 Python 的模块搜索路径
import sys
# 打印所有搜索路径(列表形式)
print(sys.path)
3. 解决「导入失败」的方法
方法 1:把模块 / 包放在当前执行目录
比如main.py在project/目录,把student_system包也放在project/里,就能直接导入。
方法 2:临时添加搜索路径(适合临时测试)
# main.py
import sys
# 把包所在的目录添加到sys.path(替换成你的实际路径)
sys.path.append("/Users/xxx/Documents/my_project")
# 现在就能导入了
import student_system
方法 3:设置环境变量(永久生效)
在系统中设置PYTHONPATH环境变量,值为你的包 / 模块所在目录。
五、最佳实践
(1)命名规范:
模块 / 包名用小写字母,多个单词用下划线(如 data_handler.py);
避免与 Python 内置模块重名(如不要命名为 math.py)。
(2)避免循环导入:模块 A 导入模块 B,模块 B 又导入模块 A,会导致报错,需重构代码(如提取公共逻辑到新模块)。
(3)第三方包管理:
用 pip install 包名 安装第三方包(如 pip install requests);
用 requirements.txt 记录项目依赖:
requests==2.31.0
numpy==1.26.0
(4)模块测试:利用 if __name__ == "__main__" 编写模块自测代码,不影响导入使用。
更多推荐



所有评论(0)