Python跨目录导入子模块报ModuleNotFoundError的解决方法
Python抛出ModuleNotFoundError: No module named 'utils'的本质是:Python解释器默认只会将执行命令时的工作目录、脚本所在目录加入模块搜索路径列表sys.path。当你直接进入tests/目录运行test.py,或是在notebooks/目录启动Jupyter时,当前工作目录是子文件夹,不在项目根目录层级,解释器自然搜索不到上层的utils包。
手动硬编码绝对路径追加到sys.path属于临时hack方案,可移植性极差,不符合Python项目的通用开发规范。
1. 单元测试场景:使用模块模式执行命令(零代码修改,适配绝大多数开源项目惯例)
不需要修改任何导入语句,始终在**项目根目录(即包含utils、tests文件夹的Project层级)**执行命令,通过Python的-m参数以模块方式运行测试:
# 先切换到项目根目录,再执行 python -m tests.test
如果使用pytest作为测试框架更简单:pytest默认会自动将执行命令时的当前工作目录加入模块搜索路径,只需要在项目根目录直接运行pytest命令,即可自动发现并执行所有测试用例,不需要额外配置。
2. 全场景兼容:可编辑模式安装项目(一劳永逸,支持任意位置导入)
如果需要在任意子目录(包括notebooks/下的Jupyter Notebook环境)正常导入项目模块,只需要做一次简单配置:
- 第一步:在项目根目录新建
pyproject.toml文件,写入以下基础配置:
[build-system] requires = ["setuptools>=61.0"] build-backend = "setuptools.build_meta" [project] name = "your-project-name" # 替换成你的项目名即可 version = "0.1.0" packages = ["utils"]
- 第二步:激活项目对应的虚拟环境,在项目根目录执行可编辑安装命令:
pip install -e .
执行完成后,当前项目会以软链接的形式关联到虚拟环境的包目录中,后续只要使用该虚拟环境的解释器,无论你在项目的哪个子目录运行脚本、启动Jupyter,都可以直接使用from utils.test_function import some_function完成导入,路径调整、项目迁移都不会导致导入失效,是Python项目开发的通用最佳实践。
- 禁止在业务代码、测试代码中手动写
sys.path.append()追加路径,这类硬编码逻辑在环境切换、项目迁移时必然出现兼容问题 - 不要随意将子文件夹标记为IDE的源码根目录,这类配置仅在当前IDE生效,换运行环境、命令行执行时依然会报导入错误
- 运行脚本、启动Jupyter前务必确认已激活项目对应的虚拟环境,避免调用全局Python解释器导致找不到已安装的项目包
内容的提问来源于stack exchange,提问作者Jeff

