Python 编程教程 / 11 - 模块与包
第 11 章:模块与包
理解 Python 的模块系统、导入机制和包管理,组织大型项目代码。
11.1 模块基础
11.1.1 什么是模块?
一个 .py 文件就是一个模块。模块可以包含函数、类、变量。
# math_utils.py
"""数学工具模块。"""
PI = 3.14159
def add(a: int, b: int) -> int:
return a + b
def circle_area(radius: float) -> float:
return PI * radius ** 2
11.1.2 导入方式
# 导入整个模块
import math_utils
print(math_utils.add(1, 2))
# 导入特定成员
from math_utils import add, PI
print(add(1, 2))
# 别名导入
import math_utils as mu
print(mu.circle_area(5))
# 导入所有(不推荐)
from math_utils import *
11.1.3 模块的 __name__
# math_utils.py
def add(a, b):
return a + b
if __name__ == "__main__":
# 只在直接运行时执行
print(f"2 + 3 = {add(2, 3)}")
$ python math_utils.py # 输出: 2 + 3 = 5
$ python -c "import math_utils" # 不输出
11.2 包
11.2.1 包的结构
mypackage/
├── __init__.py # 包初始化(可以为空)
├── core.py # 子模块
├── utils.py
└── subpackage/
├── __init__.py
└── helpers.py
11.2.2 __init__.py
# mypackage/__init__.py
# 控制 from mypackage import * 的行为
__all__ = ["core", "utils"]
# 包级别的初始化代码
__version__ = "1.0.0"
# 便捷导入
from .core import important_function
from .utils import helper
11.2.3 使用包
# 方式一:完整路径
from mypackage.core import important_function
from mypackage.subpackage.helpers import helper
# 方式二:通过 __init__.py 暴露的接口
from mypackage import important_function
# 方式三:导入子包
import mypackage.subpackage.helpers
11.3 导入机制
11.3.1 搜索路径
import sys
print(sys.path)
# [
# '', # 当前目录
# '/usr/lib/python312.zip',
# '/usr/lib/python3.12',
# '/usr/lib/python3.12/lib-dynload',
# '/home/user/.venv/lib/python3.12/site-packages',
# ]
# 动态添加搜索路径
import sys
sys.path.insert(0, "/my/custom/path")
sys.path.append("/another/path")
11.3.2 导入过程
import mymodule
1. 搜索模块(sys.path)
2. 检查 sys.modules 缓存
3. 加载模块代码
4. 执行模块顶层代码
5. 将模块绑定到 sys.modules["mymodule"]
import sys
# 查看已导入的模块
print("json" in sys.modules) # True(已被标准库预导入)
# 查看模块信息
import json
print(sys.modules["json"]) # <module 'json' from '...'>
11.3.3 相对导入
# mypackage/core.py
# 相对导入(使用 . 或 ..)
from . import utils # 同包的 utils
from .utils import helper # 同包的 utils 中的 helper
from .. import other_module # 上级包的 other_module
from ..subpackage import helpers # 同级子包
# ⚠️ 相对导入只能在包内部使用,不能在脚本顶层使用
11.3.4 导入的最佳实践
# ✅ 标准库 → 第三方库 → 本地模块(用空行分隔)
import os
import sys
from datetime import datetime
import requests
import numpy as np
from myproject.utils import helper
from myproject.models import User
11.4 高级主题
11.4.1 命名空间包(PEP 420)
# 允许将包分散在多个目录中
# 目录结构 A:
# mynamespace/package_a/module_a.py
# 目录结构 B:
# mynamespace/package_b/module_b.py
# 不需要 __init__.py
# 两个目录都加入 sys.path 后,可以同时导入
from mynamespace.package_a import module_a
from mynamespace.package_b import module_b
11.4.2 延迟导入
def process_image(path: str):
"""只在函数调用时才导入(减少启动时间)。"""
from PIL import Image # 延迟导入
img = Image.open(path)
return img
11.4.3 __all__ 控制导出
# utils.py
__all__ = ["public_function", "PublicClass"]
def public_function():
pass
def _private_function():
pass
class PublicClass:
pass
class _PrivateClass:
pass
from utils import * # 只导入 public_function 和 PublicClass
11.4.4 模块级别魔术变量
# mymodule.py
print(__name__) # "__main__" 或 "mymodule"
print(__file__) # /path/to/mymodule.py
print(__doc__) # 模块文档字符串
print(__package__) # 包名或 None
print(__loader__) # 模块加载器
print(__spec__) # 模块规范
11.5 常用标准库模块速查
| 模块 | 用途 |
|---|---|
os | 操作系统接口 |
sys | 系统参数和函数 |
pathlib | 面向对象的路径操作 |
json | JSON 编解码 |
re | 正则表达式 |
datetime | 日期和时间 |
collections | 高级容器 |
itertools | 迭代器工具 |
functools | 函数工具 |
typing | 类型注解 |
logging | 日志 |
unittest | 单元测试 |
argparse | 命令行参数 |
subprocess | 子进程管理 |
threading | 线程 |
multiprocessing | 多进程 |
asyncio | 异步 I/O |
dataclasses | 数据类 |
abc | 抽象基类 |
contextlib | 上下文管理器工具 |
11.6 注意事项
🔴 注意:
- 循环导入会导致
ImportError,使用延迟导入或重构代码解决 from module import *会污染命名空间,避免使用- 相对导入在直接运行脚本时不工作,使用
-m标志运行 - 不要在
__init__.py中放太多逻辑
💡 提示:
- 使用
__all__明确导出接口 - 包内的模块之间使用相对导入
- 使用
if __name__ == "__main__"保护脚本入口 - 大型项目使用
src/布局避免导入问题
📌 业务场景:
# 项目结构
# myproject/
# ├── __init__.py
# ├── config.py # 配置
# ├── models/ # 数据模型
# │ ├── __init__.py
# │ ├── user.py
# │ └── order.py
# ├── services/ # 业务逻辑
# │ ├── __init__.py
# │ └── order_service.py
# └── api/ # API 接口
# ├── __init__.py
# └── routes.py
# services/order_service.py
from ..models.user import User
from ..models.order import Order
from ..config import settings
class OrderService:
def create_order(self, user: User, items: list) -> Order:
...