包Package是组织Python模块的目录结构,用于管理复杂项目中的代码依赖,版本控制和分发。
包必须包含一个特殊文件 init.py (可以为空),用于标识该目录是一个Python包。
包的典型结构
my_package/
├── __init__.py # 包初始化文件(必填)
├── module1.py # 子模块1
├── module2.py # 子模块2
└── subpackage/ # 子包
├── __init__.py
└── module3.py
包的核心结构
1.创建包
创建目录并添加 init.py
bash
mkdir mypackage
touch mypackage/__init__.py
添加模块文件
bash
echo "def greet(): print('Hello from mypackage!')" > mypackage/greeting.py
2.导入包中的模块
绝对导入
python
from mypackage.greeting import greet # 导入子模块的函数
greet() # 输出:Hello from mypackage!
相对导入(仅在包内部使用)
python
# mypackage/subpackage/__init__.py
from ..greeting import greet # 导入父包的模块
3.包的初始化
init.py 用于包的初始化逻辑,例如:
导入子模块供外部直接使用;
定义包级别的变量或函数。
python
# mypackage/__init__.py
from .greeting import greet
from . import subpackage
__version__ = "1.0.0" # 包版本号
4.安装本地包
使用 setup.py 安装(适用于开发模式)
python
# setup.py
from setuptools import setup, find_packages
setup(
name="mypackage",
version="1.0.0",
packages=find_packages(),
)
bash
pip install -e . # 安装为可编辑模式
5.发布到PyPI
生成源发布包和二进制分发包:
bash
python setup.py sdist bdist_wheel
使用twine上传到PyPI:
bash
pip install twine
twine upload dist/*
包的高级特性
1.命名空间包(Python 3.3+)
定义:无需 init.py 的包(通过 path 属性动态加载模块);
优势:支持分布式包结构;
示例结构:
namespace_package/
├── subpackage1/
│ └── module.py
└── subpackage2/
└── module.py
2.条件导入
根据Python版本或环境选择性导入模块:
python
try:
from urllib.parse import urlparse # Python 3
except ImportError:
from urlparse import urlparse # Python 2
3.管理依赖
使用 requirements.txt 声明依赖:
requests>=2.26.0
numpy==1.21.0
通过 setup.py 指定依赖:
python
setup(
install_requires=[
"requests>=2.26.0",
"numpy>=1.21.0"
]
)
实践
1.模块命名规范
使用小写字母和下划线(如database.py);
避免与标准库模块同名(如 json.py 会导致冲突)。
2.避免循环导入
重构代码,将公共逻辑提取到独立模块;
将导入语句放在函数内部(延迟导入)。
3.控制导入内容
使用 all 变量定义 from package import * 时导入的内容
python
# mypackage/greeting.py
__all__ = ["greet"] # 仅允许导入greet函数
4.版本管理
在 init.py 中定义 version;
使用 setuptools_scm 自动管理版本
常见问题
1.ModuleNotFoundError
python
from mypackage import module # 报错:No module named 'mypackage'
解决:
确保当前目录包含 mypackage ;
将包路径添加到 sys.path:
python
import sys, os
sys.path.append(os.path.abspath("..")) # 假设包在上级目录
2.循环导入
python
# module1.py
from module2 import func2
# module2.py
from module1 import func1 # 循环导入错误
解决:
将公共代码提取到 common.py;
延迟导入(将导入语句放在函数内部)。
3.包测试
在 setup.py 中添加测试命令:
python
setup(
test_suite="tests"
)
使用 pytest 运行测试:
bash
pip install pytest
pytest tests/