在 Linux 和 macOS 上执行
python3 -m venv .venv,并不会复制一份 Python。venv 里的 python 只是一个软链接,指回系统解释器;标准库同样没有被复制,真正属于 venv 的只有 site-packages 里的第三方包。这意味着一旦系统 Python 被升级、移动或删除,venv 可能直接失效,也可能在毫无提示的情况下改用另一个 Python 继续运行。
用ls -la .venv/bin/能看到 python、python3、python3.12 全是软链接,readlink -f追下去最终都指向/usr/bin/python3.12。venv 的 pyvenv.cfg 里写着home = /usr/bin,Python 启动时靠它找到真正的解释器和标准库。
实测一个 venv 目录约 12M,几乎全是 pip;解释器和几十兆的标准库都不在里面。把 venv 改名或移动后,pip 等命令行脚本会因 shebang 里的绝对路径失效而报 bad interpreter,venv 不可迁移。
用--copies建 venv 只复制了二进制,标准库仍是借用的。当 base Python 消失时,软链接版直接报 No such file or directory,而 --copies 版会静默回退到编译时的 prefix,可能悄悄换用另一套标准库,引发难以排查的 ImportError。
这种设计是有意为之:venv 追求轻量、创建快、可随时丢弃,系统打安全补丁时所有 venv 自动受益。代价是 venv 的稳定性完全取决于它指向的那个解释器。
应对办法是掌控自己的基础解释器:用 uv 或 pyenv 安装固定版本的 Python 再建 venv,锁定依赖并随时重建;Docker 多阶段构建时保证运行阶段与构建阶段使用相同基础镜像和相同路径;目标机器可能没有 Python 时,直接连同解释器一起打包分发。
