许多Python用户错误地认为是由
bin/activate
脚本执行的对
$PATH
的修改定义了虚拟环境。但这并不是真的——
activate
脚本只是一个方便的工具,对Python没有任何影响,它仅仅配置你的环境以更轻松地访问venv。
Python虚拟环境是由运行时在其中发生的对
sys.path
的更改以及Python自动发现库目录相对于
python[3[.n]]
解释器可执行文件的文件系统位置而定义的。所有进程环境变量,包括
$PATH
和
$VIRTUAL_ENV
,对Python内部的虚拟环境都是无关紧要的。任何使用环境变量进行检测的操作实际上只是检查是否已运行
activate
脚本。正如Martin所指出的那样,
activate
脚本并不是在venv中运行的先决条件。
如果您在
/home/me/my_venv/
中有一个虚拟环境,那么先运行
/home/me/my_venv/bin/activate
,然后再运行
python3
将会让您在该虚拟环境内运行REPL。但是
不使用activate
也可以通过运行/home/me/my_venv/bin/python3
来实现。两种方法的
sys.path
都是相同的,但是
$PATH
会有所不同,
$VIRTUAL_ENV
也不会被设置。(试一下就知道!)
因此,检测venv的关键在于当解释器从其安装路径以外的位置运行时,
sys.path
如何更改,这始于修改后的
sys.prefix
。
sys.real_prefix
是 virtualenv
包用来设置的。具有讽刺意味的是,这会引起问题,因为venv
未能检测到它正在运行在virtualenv
内部,所以virtualenv
在其 v20重写中删除了 sys.real_path
。事实上,从v20开始,如果可用,virtualenv
使用标准库的venv
模块创建其虚拟环境。(在当前支持的所有Python版本中都是可用的。)
因此,对于所有当前支持的Python版本(3.7-3.11),以下内容将有效地检测虚拟环境,而不依赖于$PATH
或$VIRTUAL_ENV
。(我保留了sys.real_path
检查,即使它很少成功并且表示非常过时的virtualenv
包。)
def in_venv() -> bool:
"""Determine whether Python is running from a venv."""
import sys
if hasattr(sys, 'real_prefix'):
return True
pfx = getattr(sys, 'base_prefix', sys.prefix)
return pfx != sys.prefix
然而,这仍然无法检测到一种非常特定的“虚拟”环境:已完全与系统安装分离的Python解释器分发。它们不会被注册为虚拟环境,因为sys.base_path
将与sys.prefix
相同-它们都将指向运行时的安装目录。
例如,在Windows上,ActiveState Python将在创建在系统上的每个项目实例中安装一个供应商提供的解释器二进制文件。该运行时可能具有类似于c:\users\$name\appdata\local\activestate\cache\$random
的sys.prefix
,并且sys.base_prefix
将是相同的。一些Node.js软件包也会使用供应商提供的Python安装程序执行类似的操作。
在这些情况下,sys.path
也将完全位于sys.prefix
路径下,使得安装技术上根本不是一个虚拟环境。它只是一个非系统的、供应商提供的Python运行时环境,与任何系统运行时没有连接或依赖关系。这些环境要可靠地检测起来要困难得多,并且编码假设在这些条件下要做什么是一个更加棘手的问题。
md5sum /tmp/bar/bin/python /usr/bin/python b35da8492c4ddb3e3413411e574db63a /tmp/bar/bin/python b35da8492c4ddb3e3413411e574db63a /usr/bin/python
。而我的理解是,我必须通过执行bin/activate
来激活环境。 - zhenechcd /path/to/virtualenv
然后运行bin/python
。 - Martijn PietersVIRTUAL_ENV
环境变量本身并不被 Python 二进制文件使用;例如VIRTUAL_ENV=/path/to/virtualenv /usr/bin/python
并不能启用它。 - Martijn Pieters