ModuleNotFoundError 模块找不到:No module named 'xxx' 速查
更新时间:2026-10-24。FAQ 速查页,面向刚在 Linux/macOS 上搭 Python 环境、一跑脚本就撞
ModuleNotFoundError的同学。这个报错字面上只有一句话——解释器在它知道的所有路径里都没找到这个模块——但「没找到」背后的原因收敛在六根轴上:根本没装、装到了另一个解释器、sys.path 里没那个目录、pip 包名和 import 名对不上、虚拟环境没激活或串了、相对导入跑出了包边界。顺一遍基本必中。如果你是ImportError: cannot import name 'xxx'(模块找到了、里面的名字找不到),那归 NameError/ImportError 名字无法导入速查 管。
本文要回答的问题
No module named 'xxx'和No module named 'xxx.yyy'; 'xxx' is not a package差在哪?- 明明
pip install成功了,为什么运行时还报找不到? - 怎么确认 pip 装包用的解释器和跑脚本用的解释器是同一个?
- 为什么有的包装的时候叫一个名、import 的时候叫另一个名?
- 直接
python xxx.py跑包内文件为什么会炸出相对导入错误?
一、报错原文与典型现象
报错就长在 traceback 最后一行,但几个变体要分清(工程路径以 /proj/demo 占位):
$ python3 /proj/demo/main.py
Traceback (most recent call last):
File "/proj/demo/main.py", line 3, in <module>
import requests
ModuleNotFoundError: No module named 'requests'$ python3 /proj/demo/main.py
ModuleNotFoundError: No module named 'yaml'
# 但你明明 pip install yaml 成功了——实际要装的是 pyyaml$ python3 -m pkgutil
ModuleNotFoundError: No module named 'demo.utils'; 'demo' is not a package读报错先抓模块名:'requests' 这类顶层名找不到,是装没装、装哪了的问题;'demo.utils'; 'demo' is not a package 是路径层的问题——解释器把别的东西(比如同名的 demo.py 文件)当成了 demo,它当然没有 utils 这个子模块。两个分支走的排查路线完全不同。
二、病因处置速查表
| 报错现象 / 场景 | 可能原因 | 快速验证 | 处置 |
|---|---|---|---|
| 任何机器上都报找不到 | 包根本没装 | python3 -m pip show 包名 无输出 | python3 -m pip install 包名 |
| 装了仍找不到 | pip 和 python 不是同一个解释器 | which python3 对比 python3 -m pip -V 里的路径 | 一律用 python3 -m pip install 装 |
| 终端能 import,脚本/IDE 里不能 | venv 没激活或 IDE 选了别的解释器 | python3 -c "import sys; print(sys.executable)" | 激活 venv;IDE 里指到 venv 的 python |
| 装的是 A 包,import B 报错 | 包名与导入名不一致 | 看包文档的 Quickstart 里的 import 写法 | 装正确发行名,import 它的导入名 |
| 报 'xxx' is not a package | 本地同名文件/目录遮蔽了真包 | python3 -c "import xxx; print(xxx.__file__)" 看落在哪 | 改掉本地同名文件/目录 |
| 脚本挪了个目录就找不到自家模块 | sys.path 只含脚本所在目录,不含项目根 | 打印 sys.path 对比项目根 | 从项目根用 python3 -m 包.模块 跑 |
| 报 attempted relative import beyond top-level package | 把包内文件当脚本直接跑 | 报错行是 from ..xxx import yyy | 退到项目根用 -m 方式运行 |
| 装到了用户目录但跑在 sudo 下 | --user 装的包 root 看不见 | python3 -m pip show 查 Location | 别用 sudo 跑脚本;装进 venv |
三、排查决策图
下面这张图是标准排查路线,颜色按角色区分:红是报错入口与命中的根因,蓝是排查动作,绿是通过分支,橙是修复动作,紫是防复发沉淀。
读这张图抓住一个分水岭:先跑 python3 -m pip show。查不到记录,是「装」这层的事;查得到却仍报错,才轮到「解释器错配」「同名遮蔽」「sys.path」这三条右支。不要一上来就反复重装——装错环境的话重装一百次也还是装进错的地方。
四、逐条排查展开
第一步:用「python3 -m pip」绑定解释器。 这个报错超过一半的真凶是:系统里有两个以上 Python(系统自带、自己装的、venv 里的),pip 命令挂在 A 上,python3 跑的是 B。终结这类幻觉的做法是永远不要裸敲 pip install,改成:
python3 -m pip install requests
python3 -m pip show requests
# Location 一行告诉你包装进了哪个 site-packages
python3 -c "import sys; print(sys.executable)"pip show 的 Location 必须落在 sys.executable 所属解释器的 site-packages 里,对不上就是装错环境。
venv 混用是桌面开发的固定剧本。 终端里 source venv/bin/activate 后装好了包,换个终端窗口(没激活)跑脚本就炸;或者 IDE 的解释器还指着系统 Python。确认方法统一是打印 sys.executable——在出问题的那个运行环境里打,不是在你以为的环境里打。IDE 里把解释器路径指到 /proj/demo/venv/bin/python 即可。
包名 ≠ 导入名,查文档别猜。 pip 上的发行名和 import 时的模块名经常不一致:pip install pyyaml 对应 import yaml,Pillow 对应 PIL,opencv-python 对应 cv2,scikit-learn 对应 sklearn。报 No module named 'yaml' 时去装 yaml 是南辕北辙。拿不准就 python3 -m pip index versions 包名 或直接翻官方文档的安装小节。
同名遮蔽:你写的文件把真包盖住了。 项目里随手起的 requests.py、demo.py、或者一个没带 __init__.py 的 demo/ 目录,都会被解释器优先捡到。一锤定音的确认:
python3 -c "import requests; print(requests.__file__)"
# 落在 /proj/demo/requests.py 就是遮蔽;落在 site-packages 才是真包改名本地文件,顺手删掉它旁边生成的 __pycache__。
跑法决定 sys.path。 直接 python3 /proj/demo/pkg/mod.py 时,sys.path 的第一项是 pkg/ 而不是项目根,from ..utils import x 这类相对导入就越界了。正确跑法是退到项目根:cd /proj/demo && python3 -m pkg.mod。这不是玄学,是 Python 的模块定位规则。
别用 sudo 修环境。 sudo python3 时 --user 装的包看不见、环境变量也变,问题只会更乱。权限类安装失败请转 pip install 安装失败速查 的 --user 与 venv 方案。
多版本并存时的点名技巧。 机器上同时有 python3.11 和 python3.12 时,「我装过了」常指 3.11 而跑脚本的是 3.12。把命令里的 python3 全部换成带小版本号的完整名再试一遍:python3.12 -m pip install requests、python3.12 /proj/demo/main.py。解释器、安装、运行三者用同一个名字,错配空间就被压没了。容器和 CI 里同理,镜像基座换版本后第一件事就是把所有脚本里的 python3 点名核对一遍。
还有一个隐蔽变体:包在、子模块不在。 报 No module named 'requests.adapters2' 而 import requests 正常,说明你引的是这个包从未提供过的内部路径——第三方教程常拿内部实现举例,版本一升级内部文件改名就炸。对照官方文档的公开 API 路径改写,别深引下划线开头的内部模块。
CI 与 crontab 是错配高发区。 交互终端里一切正常、定时任务里却报模块找不到,因为 cron 的 PATH 极简、也不继承你激活的 venv——脚本里写死解释器绝对路径(如 /proj/demo/venv/bin/python main.py),比依赖环境变量稳得多。CI 流水线同理,每一步都显式 python3 -m pip install -r requirements.txt,别假设上一步装的环境还在。
五、规范做法与预防
- 一个项目一个 venv:
python3 -m venv venv && source venv/bin/activate,依赖互不串味。 - 只认
python3 -m pip:写进项目 README 第一条,从源头消灭「装错解释器」。 - requirements.txt 入库:
python3 -m pip freeze > requirements.txt,新机器一条命令还原。 - 文件名避开库名:新建脚本前想一下会不会和常用包撞名(
requests.py、email.py、test.py都是高危)。 - 入口统一用 -m 跑:README 里写
python3 -m pkg.main,不给相对导入越界的机会。 - CI 里跑一次干净环境安装:
pip install -r requirements.txt && python3 -c "import 你的包",装错名、漏依赖当天现形。
这一篇在知识体系里的位置
本篇是 Python 排错速查簇的入口篇,定位「模块整个找不到」:模块找到了但里面的名字导不出看 NameError/ImportError 名字无法导入速查;装包这一步本身就失败(源不通、证书报错、编译失败、权限拒绝)看 pip install 安装失败速查;Python 环境从零搭建的概念底座看 Python 入门导览。sys.executable / pip show / __file__ 三件确认套在一切 import 类报错里通用。
一句话总结
ModuleNotFoundError 先跑 python3 -m pip show 包名 分档:查无记录就是没装或装错了名字(注意 pyyaml/yaml、Pillow/PIL、opencv-python/cv2 这类包名与导入名错位),一律 python3 -m pip install 绑定当前解释器重装;查得到却仍报错就往右查——sys.executable 对 pip -V 确认没装错环境、import xxx; print(xxx.__file__) 排除本地同名文件遮蔽、包内文件改用 python3 -m pkg.mod 从项目根跑。一个项目一个 venv、只认 python3 -m pip、requirements.txt 入库,这个报错基本绝迹。