pip和virtualenv有什么好处?

26 投票
4 回答
11666 浏览
提问于 2025-04-16 08:44

大家都在告诉我使用 pip 和 virtualenv,但没有人能解释这比我现在的做法好在哪里。大家使用 pip 和 virtualenv 的主要原因似乎就是因为大家都在用它……

我相信使用 pip 和 virtualenv 有很好的理由,但我在谷歌上找不到这些理由。我希望 StackOverflow 社区的某个人能给我解释一下。

这是我目前组织 Django 项目的方式:

site/src/ : contains all python-only dependencies of my project

site/lib/ : contains symlinks to the python packages

site/[projectname]/ : contains all my project specific code

整个网站文件夹都在我的代码库里(是的,包括所有仅依赖 Python 的东西,比如 Django 本身)。

所有非 Python 依赖的东西(比如 PIL、psycopg2 等)都在 README 文件中记录,并在系统级别安装(用 apt-get install ...)。

举个例子,假设我有一个名为 "projectfoo" 的项目,它依赖于 django-1.2.3、pygeoip-0.1.3 和 psycopg2,我会有:

/usr/lib/python2.5/site-packages/psycopg2

~/projects/foo/site : checkout of my repository
~/projects/foo/site/src/django-1.2.3
~/projects/foo/site/src/pygeoip-0.1.3
~/projects/foo/site/lib/django -> symlink to ../src/django-1.2.3/django
~/projects/foo/site/lib/pygeoip -> symlink to ../src/pygeoip-0.1.3/pygeoip
~/projects/foo/site/projectfoo/

那么,这和使用 PIP/virtualenv 实际上有什么区别呢?

用我现在的方式部署项目

svn checkout https://myserver.com/svn/projectfoo/tags/1.0.0STABLE/site

用 PIP/virtualenv 部署项目

wget https://myserver.com/svn/projectfoo/tags/1.0.0STABLE/projectfoo-requirements.txt
pip install -U -E projectfoo-venv -r projectfoo-requirements.txt

用我现在的方式进行项目开发

cd ~/projects/foo/site/projectfoo
export PYTHONPATH=.:..:../lib
./manage.py runserver 0:8000

用 PIP/virtualenv 进行项目开发

workon projectfoo
cd path/to/project
./manage.py runserver 0:8000

处理非 Python 依赖的方式

非 Python 依赖的东西处理方式是一样的,我绝对不会使用 virtualenv 的 --no-site-packages 选项,并在我的服务器上安装编译器和所有构建依赖,我觉得没有人会这么做。

用我现在的方式升级 Python 依赖

我会在 src 目录下检出/解压新版本,删除旧版本,更新 lib 中的符号链接,然后提交。这样,其他所有在这个项目上工作的人在下次 svn upgit pull 时就能得到更新。有一点不太好的就是,如果 src 中的旧文件夹里有 pyc 文件,它会保留,这可以通过在更新本地副本之前删除所有 pyc 文件来避免。

用 PIP/virtualenv 升级 Python 依赖

你提交一个新的 requirements 文件版本,希望项目中的每个人在更新本地副本时能注意到新版本,然后他们运行 pip install -E projectfoo-venv -r requirements.txt

编辑: 我去掉了 pip 的 -U 选项,这在 pip 8.2 中是不需要的。

编辑: 使用 pip/virtualenv 相比我现在的做法,似乎唯一的好处是在处理需要不同版本 Python 的不同项目时。但根据我的经验,当你需要不同版本的 Python 时,通常也需要不同版本的其他系统库(如 PIL、psycopg2 等),而 virtualenv 对此没有帮助(除非你疯到使用 --no-site-package 选项,即使那样也不完整)。我能想到的唯一解决方案就是使用不同的虚拟机。

那么我错过了什么?有没有人能告诉我一个使用 PIP 或 virtualenv 比我现在做的更好的案例?

4 个回答

3

我按照你建议的方法,不使用pip或virtualenv来处理我的常规项目。 这样我可以把软件包放在特定的目录里。

+ext
  |
  |------python packages
+source
  |
  |------ project code and packages

通常在启动脚本中,我会更新PYTHONPATH。

export PYTHONPATH="";
export PYTHONPATH="${PYTHONPATH}:${workingdir}/path/to/ext";

这样做的好处是可以让项目和依赖关系保持在一个封闭的环境中。我非常赞同你的想法。

不过,我发现使用virtualenv的情况是:

  1. 当我需要尝试一些新东西的时候。
  2. 更好的是,当我想使用两个不同版本的软件包并进行比较时。
  3. 还有一种情况是,我会把不同相关的软件包放在一起,这样可以在多个项目中使用

例如:文档:我安装的一些关键软件包包括sphinx、pygraphwiz、nterworkX和一些其他可视化软件包。我在多个项目中使用这些软件包,并且把它们放在系统级别的安装之外,以保持环境的干净。

我还想让你看看:Yolk。 我觉得它和pip/virtualenv结合使用非常不错。

你可以列出软件包

yolk -l
Jinja2          - 2.5.5        - active 
Markdown        - 2.0.3        - active 
Pycco           - 0.1.2        - active 
......

并查看pypi的更新。

yolk --show-updates
Pycco 0.1.2 (0.2.0)
Sphinx 1.0.4 (1.0.5)
pip 0.8.1 (0.8.2)
9

"所有非仅限Python的依赖项(比如PIL、psycopg2等)都在README中有说明,并且是在系统级别安装的(比如用apt-get install ....)"

这样的话,你就不能为不同的项目使用不同的依赖项,也不能为不同的项目使用这些依赖项的不同版本。

这会导致一个问题,就是你本地安装的环境和生产环境(实际运行的环境)不一致,这样你在复现生产环境中的错误时可能会遇到麻烦。

如果你安装了一些系统工具,它们需要某个特定版本的依赖项,那么你就只能在所有地方都使用这个版本,这可能会导致你的项目出现问题。

另外,想要恢复被删除的模块,必须在系统的Python环境中进行。使用虚拟环境(virtualenv)可以让你设置一个独立的Python环境来测试东西,而不会影响到系统的Python安装。

我强烈建议为你的项目使用一个独立的Python环境,并使用一些工具来进一步隔离这个Python环境,比如virtualenv或zc.buildout。

PIP只是一个更简单的安装模块的方式,同时也能帮助你卸载模块。

"我绝对不想在我的服务器上使用virtualenv的--no-site-packages选项,还要安装编译器和所有构建依赖,我觉得没人会真的这么做。"

不,我使用zc.buildout,但其实效果差不多,只是工作量更少。;)

19

当你有很多项目时,virtualenv 就特别好用,因为它可以让每个项目使用不同的 Python 环境,而不是让它们都共享同一个 Python 安装。比如说,你可能有两个项目,它们对 Python 的要求不一样,这时候就会出现冲突。

撰写回答