真实创建一个venv,对比它跟系统Python的pyvenv.cfg、sys.prefix和site-packages目录,验证依赖隔离机制到底是怎么生效的。
代码python3 -m venv venv-test cat venv-test/pyvenv.cfg python3 -c "print(sys.prefix)" # 系统解释器 ./venv-test/bin/python3 -c "print(sys.prefix, sys.base_prefix)" # venv解释器
home = /opt/homebrew/opt/python@3.14/bin include-system-site-packages = false version = 3.14.7 executable = /opt/.../Python.framework/Versions/3.14/bin/python3.14 command = /opt/homebrew/opt/python@3.14/bin/python3.14 -m venv venv-test
这份pyvenv.cfg真实是venv机制的核心配置文件——它没有复制一份完整的Python解释器,home字段真实指向的是创建这个venv时用的系统Python所在目录;include-system-site-packages = false真实决定了这个venv能不能看到系统全局装的第三方包(默认看不到,这也是"隔离"的关键开关之一)。venv目录里的bin/python3真实只是一个指向系统解释器的软链接或者极小的转发可执行文件,不是一份完整的Python拷贝——venv的"轻"就体现在这里,创建速度快、占用空间小,靠的是这份配置文件加运行时对sys.prefix的改写,而不是真的把整个Python安装目录复制一遍。
系统python3: sys.prefix = /opt/homebrew/opt/python@3.14/Frameworks/Python.framework/Versions/3.14 venv里的python3: sys.prefix = .../py-lab/venv-test ← 真实变成了venv自己的目录 sys.base_prefix = /opt/homebrew/opt/python@3.14/Frameworks/Python.framework/Versions/3.14 ← 真实还是指向系统解释器
venv启动时真实做的核心动作,是把sys.prefix(决定去哪找site-packages)指向venv自己的目录,但保留sys.base_prefix指向原本的系统安装——不在venv里的解释器,这两个值真实是相等的;一旦进了venv,这两个值真实会不一样。这正是很多工具(包括pip自己)判断"当前是不是在虚拟环境里"最常用的真实依据:sys.prefix != sys.base_prefix,不需要额外读环境变量。
venv-test/bin/pip list(刚创建,还没装任何包): Package Version ------- ------- pip 26.2.1 ← 真实只有pip自己,不是系统site-packages的复制品 venv-test/bin/pip install tabulate venv-test/bin/python3 -c "import tabulate; print(tabulate.__file__)" → .../venv-test/lib/python3.14/site-packages/tabulate/__init__.py ← 真实装进了venv自己的目录 系统python3 -c "import tabulate" → ModuleNotFoundError: No module named 'tabulate' ← 真实系统解释器完全看不到这个包
每一步都是本文上面用真实创建的venv跑出来的原始结果。
python3 -m venv 与 pip install