
本文深入解释为何在已激活 conda 环境(如 nmrfilter,含 Python 3.7)中再用 python3 -m venv 创建子虚拟环境会导致依赖安装失败——根本原因在于 venv 继承的是当前 shell 的 python3 可执行文件路径,而该路径实际指向 conda 环境中的 Python 3.7 解释器;当 pip 尝试安装 numpy==1.24 时,因该版本强制要求 Python ≥3.8,安装静默跳过,导致后续运行时报 ModuleNotFoundError。
本文深入解释为何在已激活 conda 环境(如 `nmrfilter`,含 python 3.7)中再用 `python3 -m venv` 创建子虚拟环境会导致依赖安装失败——根本原因在于 venv 继承的是**当前 shell 的 python3 可执行文件路径**,而该路径实际指向 conda 环境中的 python 3.7 解释器;当 pip 尝试安装 `numpy==1.24` 时,因该版本强制要求 python ≥3.8,安装静默跳过,导致后续运行时报 `modulenotfounderror`。
在 Python 工程实践中,“conda 环境内嵌套 venv”是一种常见但极易引发隐性故障的误用模式。你的脚本看似逻辑清晰:先确保 conda 环境就绪,再创建独立 venv 并安装 requirements.txt。然而问题根源不在路径或权限,而在 Python 版本兼容性与 venv 构建机制的底层耦合。
? 关键机制:python3 -m venv 并非“全新 Python”,而是复用当前解释器
当你在已激活 conda 环境 nmrfilter(Python 3.7.16)下执行:
python3 -m venv "$script_dir/nmrfilter_env"
venv 模块并不会下载或编译新 Python,而是以当前 python3 可执行文件为模板,复制其二进制、标准库结构及 site-packages 骨架,生成一个轻量级隔离目录。此时:
- nmrfilter_env/bin/python → 符号链接或硬链接至 conda 环境中的 ~/miniconda3/envs/nmrfilter/bin/python3.7
- pip 安装行为完全受该解释器的 sys.version_info 约束
而你的 requirements.txt 中明确指定:
numpy==1.24
查阅 PyPI numpy 1.24 发布页 可确认其 Requires-Python: >=3.8。当 pip 在 Python 3.7.16 下解析该行时,直接忽略该包(不报错、不警告、不安装),这是 pip 的默认兼容性策略。因此你看到:
pip list | grep numpy # 空输出
并非安装失败,而是根本未触发安装流程。
✅ 验证方法:在 conda nmrfilter 环境中手动运行
pip install "numpy==1.24" # 输出:ERROR: Package 'numpy' requires a different Python: 3.7.16 not in '>=3.8'
⚠️ 进一步陷阱:which python3 的误导性
你的调试输出显示:
Python3 executable: /home/karl/nmrfilterv15/nmrfilter_env/bin/python3
这看似证明 venv 已生效,但注意:该 python3 是 venv 自带的 wrapper 脚本,它内部仍调用 conda 的 Python 3.7 解释器(可通过 head -1 $(which python3) 查看 shebang)。真正的解释器路径并未改变。
? 正确解法:避免嵌套,按场景选择唯一环境管理方案
| 场景 | 推荐方案 | 原因 |
|---|---|---|
| 纯 Python 项目,依赖简单 | python -m venv + pip | 轻量、标准、IDE 兼容性好 |
| 多语言/跨版本/科学计算栈 | 仅用 conda(如你的 nmrfilter) | conda 可精确控制 Python 版本、预编译二进制(如 RDKit、PyTorch)、解决 ABI 冲突 |
| 需混合 pip-only 包 + conda 包 | conda activate nmrfilter && pip install --no-deps ... | 在 conda 环境内直接 pip 安装,避免环境分裂 |
? 若坚持使用 venv,请先彻底退出 conda 环境(conda deactivate),再运行脚本。此时 python3 指向系统 Python 或 pyenv 管理的版本,可满足 numpy==1.24 要求。
? 总结:三层环境隔离的认知误区
| 层级 | 隔离维度 | 是否真正隔离 Python 解释器? |
|---|---|---|
| Conda 环境 | 解释器 + C 库 + Python 包 + 跨语言依赖 | ✅ 完全独立(不同 python 二进制) |
| venv(基于 conda Python) | site-packages + Scripts | ❌ 共享父解释器,受其版本/ABI 严格约束 |
| venv(基于系统 Python) | site-packages + Scripts | ✅ 独立解释器副本(需系统存在对应版本) |
因此,你遇到的不是 bug,而是设计使然:venv 的定位是“同一 Python 解释器下的包沙箱”,而非“跨解释器的版本调度器”。混用 conda(负责解释器层)与 venv(仅负责包层)会造成语义冲突。
✅ 最佳实践:一个项目,一种环境管理工具。你的 nmrfilter 显然属于 conda 典型场景——含 RDKit、PyTorch、numba 等需编译优化的科学包,应全程使用 conda 管理,删除 venv 步骤不仅可行,更是推荐做法。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











