必须用 python -m 启动含相对导入的文件,因直接运行会使 package 为 None,导致 .. 无参照系;正确做法是项目根目录下执行 python -m src.core.utils。

直接运行含 from .. 的文件必然报错
这不是代码写错了,而是启动方式破坏了包上下文。Python 把 python core/utils.py 当作顶层脚本,__name__ 是 '__main__',__package__ 为 None。此时 from ..utils import helper 中的 .. 根本没参照系——它不知道“上一级”是哪个包。
常见错误现象:
- 终端输出
ImportError: attempted relative import with no known parent package - 或更狠的
ValueError: attempted relative import beyond top-level package -
print(__name__, __package__)得到__main__ None(哪怕文件在src/里且有__init__.py)
唯一可靠的修复:用 python -m 启动
必须让 Python 以模块身份加载你的文件,而不是当脚本执行。这要求两件事同时满足:
- 当前工作目录是项目根目录(即包含
src/或mypackage/的那一层) - 命令中不带
.py,用完整模块路径,例如python -m src.core.utils
这时 utils.py 的 __name__ 变成 'src.core.utils',__package__ 是 'src.core',.. 才能正确指向 src。
立即学习“Python免费学习笔记(深入)”;
容易踩的坑:
-
python -m src.core.utils但当前目录在src/下 → 找不到src包 -
python -m core.utils而不是src.core.utils→ 缺少顶层包名 - 路径里漏掉某个
__init__.py(哪怕空文件)→ Python 不认那是包
想双击/直接运行?别用相对导入
如果入口文件(比如 main.py)需要被双击或 python main.py 启动,它内部就不要写 from ..。改成绝对导入:
- 确保
src/在sys.path中(开发期用pip install -e .或临时加路径) - 写
from src.utils import helper,而不是from ..utils import helper
性能与兼容性影响:
- 绝对导入在 IDE 和静态分析工具中更稳定,路径可追溯
- 相对导入只适合纯包内逻辑拆分,不适合暴露给用户直接触发的入口
- 混用两种导入方式会增加维护成本,尤其在重构包层级时
__main__ 里手动补 __package__ 是权宜之计
仅限开发调试,别放进生产代码。在入口文件顶部加这几行能绕过报错:
if __name__ == '__main__' and __package__ is None:
import os
import sys
parent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, parent_dir)
__package__ = 'src.core'
但问题在于:
- 硬编码包名,重命名包就得改这里
- 多级嵌套时
os.path.dirname嵌套容易出错 - 如果项目被 pip 安装或打包,
sys.path插入位置可能失效
真正容易被忽略的点是:**错误不是发生在导入语句本身,而是发生在你按下回车执行的那一瞬间——启动方式决定了整个模块系统的上下文是否成立。**


















