【Python】杂 - virtualenv 管理 Python 项目依赖

Posted by 西维蜀黍 on 2019-10-08, Last Modified on 2021-09-21

Background

virtualenv is a tool to create isolated Python environments.

The basic problem being addressed is one of dependencies and versions, and indirectly permissions. Imagine you have an application that needs version 1 of LibFoo, but another application requires version 2. How can you use both these applications? If you install everything into /usr/lib/python2.7/site-packages (or whatever your platform’s standard location is), it’s easy to end up in a situation where you unintentionally upgrade an application that shouldn’t be upgraded.

Or more generally, what if you want to install an application and leave it be? If an application works, any change in its libraries or the versions of those libraries can break the application.

Also, what if you can’t install packages into the global site-packages directory? For instance, on a shared host.

In all these cases, virtualenv can help you. It creates an environment that has its own installation directories, that doesn’t share libraries with other virtualenv environments (and optionally doesn’t access the globally installed libraries either).

总结来说,virtualenv 是用来隔离不同 Python 项目的开发与运行环境。一个典型的场景是,有一个基于 Python 2.7 的 Django 项目,基于的 Django 版本是 1.1,而同时我们本机上正在开发一个同样基于 Python 2.7 的 Django 项目,不同的是这个项目基于Django 1.2 版本。

我们通过 pip install django来安装 Django,而这个 Django 依赖包默认会保存在/usr/lib/python2.7/site-packages,且这两个项目均会通过访问 /usr/lib/python2.7/site-packages来完成我们的 Django 项目的编译。

这意味着,我们要么安装 1.1 的 Django 版本,要么安装 1.2的版本。

通过使用 virtualenv 后,它会在我们的工程文件夹下创建一个 venv 文件夹,里面包含了这个项目使用的 Python 可执行程序(或者称为 compiler 或者 interpreter)、所有依赖的第三方包。

最终,就解决了不同项目可能需要依赖不同版本的第三方包的问题。

使用

1 安装

# Python2 下
$ pip2 install virtualenv
# Python3 下
$ pip3 install virtualenv

2 创建Python运行环境

然后,假定我们要开发一个新的项目,需要一套独立的Python运行环境,可以这么做:

第一步,创建目录:

$ mkdir myproject
$ cd myproject/

第二步,创建一个独立的Python运行环境,命名为venv

$ virtualenv --no-site-packages venv
Using base prefix '/usr/local/.../Python.framework/Versions/3.4'
New python executable in venv/bin/python3.4
Also creating executable in venv/bin/python
Installing setuptools, pip, wheel...done.

命令virtualenv就可以创建一个独立的Python运行环境,我们还加上了参数--no-site-packages,这样,已经安装到系统Python环境中的所有第三方包都不会复制过来,这样,我们就得到了一个不带任何第三方包的“干净”的Python运行环境。


或者,我们也指定这个项目中的 Python 版本:

$ virtualenv venv -p python2.7

3 激活隔离环境

新建的Python环境被放到当前目录下的venv目录。有了venv这个Python环境,可以用source进入该环境:

$ source venv/bin/activate
(venv)$

注意到命令提示符变了,有个(venv)前缀,表示当前环境是一个名为venv的Python环境。

查看当前已经安装的包:

(venv) $ pip3 list
Package    Version
---------- -------
pip        19.2.3
setuptools 41.2.0
wheel      0.33.6

下面正常安装各种第三方包,并运行python命令:

(venv)$ pip install jinja2
...
Successfully installed jinja2-2.7.3 markupsafe-0.23
(venv)$ python myapp.py
...

venv环境下,用pip安装的包都被安装到venv这个环境下,系统Python环境不受任何影响。也就是说,venv环境是专门针对myproject这个应用创建的。

4 退出隔离环境

退出当前的venv环境,使用deactivate命令:

(venv)$ deactivate 
$ 

此时就回到了正常的环境,现在pippython均是在系统Python环境下执行。

完全可以针对每个应用创建独立的Python运行环境,这样就可以对每个应用的Python环境进行隔离。

virtualenv是如何创建“独立”的Python运行环境的呢?原理很简单,就是把系统Python复制一份到virtualenv的环境,用命令source venv/bin/activate进入一个virtualenv环境时,virtualenv会修改相关环境变量,让命令pythonpip均指向当前的virtualenv环境。

Troubleshoot

zsh: /usr/local/bin/virtualenv: bad interpreter: /usr/local/opt/python3/bin/python3.6: no such file or directory

$ pip install -U --force-reinstall virtualenv

Reference