python 模块(module)与包(package)全解析
python 的模块和包是代码组织与复用的核心机制:
- 模块(module):单个
.py文件,封装变量、函数、类等,是代码复用的最小单元; - 包(package):包含
__init__.py文件的目录,用于组织多个相关模块,实现代码的分层管理。
两者结合可将大型项目拆分为清晰的结构,避免代码冗余,提升可维护性。
一、模块(module)
1. 核心定义
一个 .py 文件就是一个模块,文件名即模块名(如 utils.py → 模块名 utils)。模块内可包含:
- 变量(全局 / 局部)、函数、类;
- 可执行代码(如测试语句、初始化操作)。
2. 模块的核心作用
| 作用 | 说明 |
|---|---|
| 代码复用 | 一次编写,多处导入使用(无需重复写代码) |
| 命名空间隔离 | 不同模块的同名函数 / 变量互不冲突 |
| 简化维护 | 按功能拆分代码,单个模块聚焦单一职责 |
3. 模块的使用(导入与调用)
(1)基础导入方式
# 1. 导入整个模块 import math # 导入python内置math模块 print(math.pi) # 调用模块中的变量:3.141592653589793 print(math.sqrt(16)) # 调用模块中的函数:4.0 # 2. 导入模块并指定别名(简化调用) import numpy as np print(np.array([1,2,3])) # 别名调用 # 3. 导入模块中的指定内容(函数/变量/类) from math import pi, sqrt print(pi) # 直接使用,无需加模块名 print(sqrt(25)) # 5.0 # 4. 导入模块中的所有内容(不推荐,易冲突) from math import * print(cos(0)) # 1.0
(2)自定义模块
步骤 1:创建自定义模块文件 my_module.py:
# my_module.py
# 定义变量
version = "1.0"
# 定义函数
def add(a, b):
return a + b
# 定义类
class calculator:
def multiply(self, a, b):
return a * b
# 可执行代码(仅模块直接运行时执行)
if __name__ == "__main__":
print("模块自身运行时执行")
print(add(2, 3)) # 5步骤 2:在其他文件中导入使用:
# main.py # 导入自定义模块 import my_module print(my_module.version) # 1.0 print(my_module.add(3, 4)) # 7 calc = my_module.calculator() print(calc.multiply(2, 5)) # 10
4. 模块的特殊属性
| 属性 | 说明 |
|---|---|
__name__ | 模块名:- 模块直接运行时为 __main__- 被导入时为模块名(如 my_module) |
__file__ | 模块的绝对路径(如 /home/user/my_module.py) |
__doc__ | 模块的文档字符串(需在模块开头用 """ 定义) |
二、包(package)
1. 核心定义
包是包含 __init__.py 文件的目录,用于管理一组相关模块(可嵌套子包)。__init__.py 可空,也可用于初始化包(如导入核心模块、定义包级变量)。
2. 包的目录结构(示例)
my_package/ # 根包
├── __init__.py # 包初始化文件
├── utils.py # 子模块1:工具函数
├── data/ # 子包
│ ├── __init__.py
│ └── handler.py # 子模块2:数据处理
└── model/ # 子包
├── __init__.py
└── user.py # 子模块3:用户模型3. 包的使用(导入与调用)
(1)基础导入方式
# 1. 导入包中的模块
import my_package.utils
print(my_package.utils.add(1, 2)) # 假设utils.py有add函数
# 2. 导入模块并指定别名
import my_package.data.handler as data_handler
data_handler.read_file("test.txt") # 调用handler.py的函数
# 3. 直接导入模块中的函数/类
from my_package.model.user import user
user = user("alice") # 实例化user类
# 4. 从包中导入模块(简化)
from my_package import utils
print(utils.add(3, 4))(2)__init__.py的作用
__init__.py 可控制包的导入行为,例如在 my_package/__init__.py 中:
# my_package/__init__.py # 1. 定义包级变量 __version__ = "2.0" # 2. 导入核心模块,简化外部调用 from .utils import add from .data.handler import read_file
此时外部可直接从包导入核心功能:
import my_package
print(my_package.__version__) # 2.0
print(my_package.add(2, 3)) # 5
my_package.read_file("test.txt")4. 包的导入规范
- 绝对导入:从根包开始导入(推荐,清晰):
from my_package.data import handler
- 相对导入:仅在包内部使用,用
.表示当前目录,..表示上级目录:
# 在my_package/model/user.py中导入同级utils from ..utils import add # .. 表示上级目录(my_package/)
三、模块 / 包的搜索路径
python 导入模块时,会按以下顺序查找:
- 当前执行脚本的目录;
- python 内置模块目录(如
/usr/lib/python3.10/); - 第三方库目录(如
site-packages/); sys.path列表中的其他路径。
查看 / 修改搜索路径
import sys
print(sys.path) # 查看当前搜索路径
# 临时添加自定义路径(仅本次运行有效)
sys.path.append("/home/user/custom_module")四、核心区别与选型
| 维度 | 模块(module) | 包(package) |
|---|---|---|
| 形式 | 单个 .py 文件 | 包含 __init__.py 的目录 |
| 作用 | 封装单一功能的代码 | 组织多个相关模块,分层管理 |
| 适用场景 | 小型功能复用(如工具函数) | 大型项目(拆分多个模块) |
| 导入方式 | 直接导入文件名 | 按目录层级导入 |
五、最佳实践
- 命名规范:
- 模块 / 包名用小写字母,多个单词用下划线(如
data_handler.py); - 避免与 python 内置模块重名(如不要命名为
math.py)。
- 模块 / 包名用小写字母,多个单词用下划线(如
- 避免循环导入:模块 a 导入模块 b,模块 b 又导入模块 a,会导致报错,需重构代码(如提取公共逻辑到新模块)。
- 第三方包管理:
- 用
pip install 包名安装第三方包(如pip install requests); - 用
requirements.txt记录项目依赖:
- 用
requests==2.31.0 numpy==1.26.0
- 模块测试:利用
if __name__ == "__main__"编写模块自测代码,不影响导入使用。
六、常见问题
- importerror: no module named 'xxx':
- 原因:模块 / 包不在
sys.path中,或名称拼写错误; - 解决:检查路径是否正确,或通过
sys.path.append()添加路径。
- 原因:模块 / 包不在
- 相对导入超出顶级包:
- 原因:在包外部使用相对导入,或相对层级超出根包;
- 解决:改用绝对导入,或确保在包内部使用相对导入。
__init__.py缺失:- 原因:python3.3+ 支持无
__init__.py的 “命名空间包”,但传统包仍需该文件; - 解决:添加空的
__init__.py文件。
- 原因:python3.3+ 支持无
到此这篇关于python 模块module与包package最佳实践的文章就介绍到这了,更多相关python 模块module与包package内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论