前言
本文大部分内容来自PEP 405 Python Virtual Environments
虚拟环境存在的原因
- python版本太多(导致其第三方的包也有众多版本),且有大版本py2和py3之分
- 有的第三方包需要依赖特定版本的包
开发者对便捷切换不同版本,解决不同版本包依赖的需求,催生了一系列的virtual environment
工具。
现存常见的虚拟环境工具有virtualenv
, venv
, pipenv
。以下主要讲venv
, 穿插其他两个第三方虚拟环境工具。
venv
venv
的优势在于轻量级,且作为标准库的一部分,天生便得到了语言设计上的支持,而不是像第三方库一样,需要顺应语言的设计。(出于稳定性与可靠性的考虑,应该首选venv
)
virtualenv
文档的首页指出,从python 3.3
开始,virtualenv
的一个子集被集成到python标准库venv
下,venv
有选择的挑选并实现了virtualenv
的部分特性。
venv
和virtualenv
相比,有以下缺点:
- 比
virtualenv
慢,因为没有使用app-data
(下载第三方包时没有使用缓存) - 没有
virutalenv
那样强的扩展性 - 不能够给任意版本创建虚拟环境,仅支持
python 3.3
及更高版本 - 不能通过
pip
升级 - 没有足够丰富的可编程API
此外,需要参考PEP 405中标准库加入venv
的动机:
Existing virtual environment tools suffer from lack of support from the behavior of Python itself. Tools such as rvirtualenv , which do not copy the Python binary into the virtual environment, cannot provide reliable isolation from system site directories. Virtualenv, which does copy the Python binary, is forced to duplicate much of Python’s site module and manually symlink/copy an ever-changing set of standard-library modules into the virtual environment in order to perform a delicate boot-strapping dance at every startup. (Virtualenv must copy the binary in order to provide isolation, as Python dereferences a symlinked executable before searching for sys.prefix.)
The
PYTHONHOME
environment variable, Python’s only existing built-in solution for virtual environments, requires copying/symlinking the entire standard library into every environment. Copying the whole standard library is not a lightweight solution, and cross-platform support for symlinks remains inconsistent (even on Windows platforms that do support them, creating them often requires administrator privileges).
运行原理
未加入venv
前, 一个python程序运行时会发生如下事情:
- python二进制文件运行时会定位它的
prefix
(存储在sys.prefix
), 并通过prefix
寻找标准库的和其他关键文件的位置,通过site
定位site-packages
的位置 - 假设没有设置
PYTHONHOME
, 可以通过在系统文件树中搜索标志性文件如os.py
来确定prefix
,如果没有找到标志性文件,则将prefix
设置为编译时硬编码在二进制文件中的prefix
为了新增venv
, PEP提议新增一步到上述的过程前,即:
- 如果
venv
生成的虚拟环境的文件夹中的pyvenv.cfg
文件存在且和python executable相邻或者是和python executable所在的文件夹是兄弟(参考后文venv
的目录结构),通过pyvenv.cfg
(文件内容参考下文pyvenv.cfg
)确定了用来构建虚拟环境的系统python executable文件路径,并将其设置为sys.base_prefix
的值, 将sys.prefix
设置为pyvenv.cfg
所在的文件夹。 - 如果
pyvenv.cfg
不存在或其中没有home
选项,则sys.prefix
将设置为sys.base_prefix
,然后接下去的步骤保持和未加入venv
前的步骤一致。 - 类比于
sys.prefix
,sys.exec_prefix
也新增加了sys.base_exec_prefix
通过sys.base_prefix
, sys.base_exec_prefix
, sys_prefix
即可确定标准库和第三方库所在。基于上述规则,则可以构建出一个与系统python环境相隔离的虚拟环境。
venv
使用方法:
|
|
或
|
|
其中path
为用户根据需求所选定虚拟环境所在文件路径,virutal_environment_name
为虚拟环境名。运行命令后将在对应路径创建virtual_environment_name
文件夹,并生成虚拟环境。
windows下文件结构为:
|
|
linux下为:
|
|
其中, pyenv.cfg
为配置文件,Scripts为从系统python复制的各个相关的python二进制可运行文件。
注意事项
虚拟环境中并不存在所有必须的文件,使用venv
生成的虚拟环境不包括头文件,标准库,DLLs(这些都是使用系统的)。这样便存在一个问题,当虚拟环境的python executable是采取复制这一形式时,若系统的python升级了,可能导致虚拟环境运行代码时出错(因为所写的代码可能和标准库不匹配了)。可以使用--upgrade
选项进行解决。
pyenv.cfg
包含以下几个选项:
home
, 指明虚拟环境所复制的系统python executable的路径include-system-site-packages
, 含义见下文version
include-system-site-packages
选项
include-system-site-packages
为true
表明会使用系统中的python的site-packags
。此外,重要的一点是搜索路径的先后顺序,当该选项为true
时,会先搜索虚拟环境中安装的包,其次才会去系统site-packages
中寻找。
生成虚拟环境时复制python executable而不是symlinks
的原因
- 不是所有的windows平台都支持
symlinks
, 且即使支持也需要管理员权限 - On OS X framework builds of Python, sys.executable is just a stub that executes the real Python binary. Symlinking this stub does not work; it must be copied.
在支持
symlinks
的windows系统下可以使用--symlinks
选项。
EnvBuilder
提供定制化
待续
virtualenv
PEP 405对virtualenv
的评价:
On POSIX systems where the installed Python’s include files are found in
${base_prefix}/include/pythonX.X
, virtualenv creates${venv}/include/
and symlinks${base_prefix}/include/pythonX.X
to${venv}/include/pythonX.X.
On Windows, where Python’s include files are found in{{ sys.prefix }}/Include
and symlinks are not reliably available, virtualenv copies{{ sys.prefix }}/Include
to${venv}/Include
. This ensures that extension modules built and installed within the virtualenv will always find the Python header files they need in the expected location relative tosys.prefix
. This solution is not ideal when an extension module installs its own header files, as the default installation location for those header files may be a symlink to a system directory that may not be writable. One installer,pip
, explicitly works around this by installing header files to a nonstandard location${venv}/include/site/pythonX.X/
, as in Python there’s currently no standard abstraction for a site-specific include directory.
因为使用太少,不做过多评价,待续
pipenv
(我对pipenv
的认知还停留在其莫名奇妙的卡住不动
上
使用太少,不做过多评价,待续
pyenv
待续
virtualenvwrapper
待续
poetry
待续