Python3.9无需修改子目录第三方源码解决ModuleNotFoundError报错
你的项目目录结构如下:
dir1/ ├── dir2/ │ ├── file1.py │ └── file2.py └── file3.py
调用链路为file3.py调用file1.py内函数,file1.py调用file2.py及dir2目录下其他同目录文件。dir2是从Github拉取的开源项目,内部统一使用平级导入写法(如import file2),直接运行时该行导入会触发ModuleNotFoundError。手动修改为from dir2 import file2虽然能解决问题,但每次拉取上游更新都要重复修改所有内部导入语句,成本过高。当前运行环境为Python 3.9.12,需要无侵入、不修改dir2内部代码的解决方案。
以下方案均不需要修改dir2目录下的原有代码:
方案1:入口文件动态添加模块搜索路径(最推荐)
在你自己维护的项目启动入口(即file3.py,或项目最先执行的顶层文件)的最顶部,在导入任何dir2下的模块之前,把dir2的绝对路径插入到Python模块搜索路径列表的最前端,代码示例:
import sys from pathlib import Path # 将dir2目录加入模块搜索优先级最高的位置 sys.path.insert(0, str(Path(__file__).resolve().parent / "dir2")) # 之后正常导入dir2下的模块即可,内部平级导入不会再报错 from dir2 import file1
原理:Python执行导入语句时,会按照sys.path列表的顺序逐路径查找目标模块,把dir2目录加入搜索路径后,dir2内部执行import file2时就能直接匹配到对应文件,完全适配dir2内所有同目录平级导入的写法。
注意:路径插入代码必须放在所有dir2相关导入语句之前,否则不生效。
方案2:临时配置环境变量(适合临时调试)
启动脚本时通过环境变量临时把dir2路径加入Python搜索路径,不需要修改任何项目代码:
- Linux/macOS 终端执行:
PYTHONPATH=./dir1/dir2:$PYTHONPATH python ./dir1/file3.py - Windows CMD 执行:
set PYTHONPATH=.\dir1\dir2;%PYTHONPATH% && python .\dir1\file3.py
该方案仅对当前单次启动生效,不需要改代码,但每次运行都要手动加环境变量,不适合长期使用。
方案3:本地可编辑安装dir2包
如果项目使用虚拟环境管理依赖,可以在项目根目录编写一个最简化的pyproject.toml配置文件(该文件放在你自己的项目维护目录下,不需要提交到上游dir2的仓库,即使拉取上游更新覆盖了dir2内的文件,该配置也不受影响),配置内容:
[build-system] requires = ["setuptools>=61.0"] build-backend = "setuptools.build_meta" [project] name = "dir2-local" version = "0.0.0" packages = ["dir2"]
配置完成后在项目根目录执行pip install -e .,安装完成后Python解释器会自动识别dir2为可导入的本地包,dir2内部的平级导入可以正常执行,不需要额外修改启动代码。
内容的提问来源于stack exchange,提问作者PeriodicParticle

