Python import 是动态加载模块、构建命名空间、处理依赖的过程;模块是.py文件,包是含__init__.py的目录;需合理组织项目结构(如src布局)、避免循环导入、用python -m运行确保路径正确。
Python 的 import 机制不是简单的“把代码复制进来”,而是动态加载模块对象、构建命名空间、处理依赖关系的过程。理解它,才能合理组织项目、避免循环导入、正确发布包、调试导入错误。
模块(.py 文件)是 import 的基本单位
每个 .py 文件默认就是一个模块,文件名(不含 .py)即模块名。import 时 Python 会按 sys.path 列表顺序查找该名字对应的文件:
- 先查内置模块(如 sys、json),命中则直接加载
- 再依次检查 sys.path 中的目录:脚本所在目录、PYTHONPATH 路径、标准库路径、site-packages 等
- 找到 xxx.py 就编译为字节码(.pyc),执行其顶层代码,生成 module 对象并缓存到 sys.modules
注意:重复 import 同一模块不会重新执行,而是直接返回缓存对象——这是实现单例和避免重复初始化的关键。
包(含 __init__.py 的目录)支持层级导入
一个普通目录只要包含空文件 __init__.py(Python 3.3+ 可省略,但显式保留更清晰),就成为包。包允许用点号分隔的层级结构,比如 from mypackage.submodule import func。
- __init__.py 可为空,也可定义 __all__ 控制 from package import * 导入的内容
- 包内模块可通过相对导入(from . import module 或 from ..utils import helper),但仅限在包内模块中使用,且必须以模块方式运行(不能直接 python submodule.py)
- 绝对导入更推荐:from mypackage.utils import log,清晰、可预测、易重构
项目结构要兼顾可运行性与可安装性
常见错误是把脚本和模块混放,导致导入失败或无法 pip install。推荐结构:
myproject/ ├── pyproject.toml # 定义构建系统、依赖、元数据(现代标准) ├── src/ │ └── mypackage/ # 实际代码放 src 下,避免本地开发时意外 import 当前目录 │ ├── __init__.py │ ├── core.py │ └── utils/ │ ├── __init__.py │ └── helpers.py ├── tests/ │ └── test_core.py └── scripts/ └── run_app.py # 入口脚本,通过 -m 方式调用:python -m mypackage.core
关键点:
- 用 src 目录隔离源码,配合 pyproject.toml 中的 packages = [{include = "mypackage", from = "src"}],确保 pip install 正确打包
- 入口脚本不直接 import 同级模块,而是用 python -m mypackage.main,让 Python 把 src 加入 sys.path
- 测试文件应能独立发现和运行,pytest 默认支持从项目根运行,自动识别 src 下的包
常见导入问题与排查方法
遇到 ImportError 或 ModuleNotFoundError,别急着改 sys.path:
- 运行 python -v -c "import mypackage" 查看详细导入路径和失败点
- 检查当前工作目录是否影响了 sys.path(尤其 IDE 中默认工作目录可能不是项目根)
- 确认 __init__.py 存在且未报语法错误(它被导入时也会执行)
- 循环导入典型表现:A.py 导入 B,B.py 导入 A,且都在顶层执行语句。解法是延迟导入(函数内 import)或重构依赖
- 虚拟环境未激活或 pip install -e . 没运行,会导致本地修改不生效
掌握 import 的实际行为,比死记语法更重要。它决定了你的代码能否被他人复用、能否在不同环境中稳定运行。









