包Package

包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/