python新手需要克服的障碍之一就是弄懂python如何安装包和进行包管理的生态系统。本篇博客是基于对"python程序员训练课程"中的材料希望能向python新的使用者解释pip和virtualenv。
前提
"python程序员训练课程"是面向已经掌握了一门和多门程序语言的开发者,所以我们认为你应该具有了相当的技术知识,如果你能熟练自如的使用命令行那将会有帮助。下面的例子用了bash,它是Macs和大多数Linux系统的缺省交互shell。但用的命令足够简单使其概念对其他的终端如PowerShell for Windows的使用者也是能理解的。
pip
我们开始下潜。pip是Python Packge Index中用于安装包的工具。PyPI(你偶然也会碰到以The Cheeseshop的形式出现)是开源第三方python包的库。如同RubyGems之如Ruby、PHP’s Packagist,CPAN之如Perl、NPM之如Node.js。
python事实上有另一个更早期的包管理工具叫easy_install,在你安装python时会自动安装。由于许多原因,pip相对于easy_install具有巨大的优势,这样在使用中便逐步取代了。如下所示,你能用easy_install来安装pip:(python3以上都自带了pip)
$ sudo easy_install pip
然后你能用pip来安装其他的包(在下面的例子中,我们安装Django):
$ sudo pip install django
这里,我们对Django在系统上进行了全局式的安装。但在大多数场合,你不应该对包进行全局式安装。继续阅读你会找到原因。
virtualenv
virtualenv解决了一个非常具体的问题:它允许在一台计算机上同时存在许多有不同要求(常常是相互冲突)的Python项目。
它解决了什么问题呢?
为了演示这个问题,让我们假装virtualenv并不存在。想象我们正在写一个程序它需要HTTP requests对远端的web服务器请求,我们准备用Requests库,它对我们要完成的事是非常棒的。象上面我们看到的那样,我们能用pip来安装Requests,但是pip准备将其安装到你计算机的什么地方呢?如果我试着运行pip install requests将会发生下面的事:
$ pip install requests
Downloading/unpacking requests
Downloading requests-1.1.0.tar.gz (337kb):337kb downloaded
Running setup.py egg_info for package requests
Installing collected packages: requests
Running setup.py install for requests
error: could not create '/Library/Python/2.7/site-packages/requests':Permission denie
哎哟! 看起来象是pip正将包安装到/Library/Python/2.7/site-packages/requests之中。在site-packages中安装的任何东西都能被导入到你的程序中去。
我们之所以看到这个错误,是因为/Library/(在Mac中)目录对"普通用户"是不可写的。 为了修复这个错误,我们能运行sudo pip install requests (sudo 表示"以超级用户身份运行这条命令")。这样一来,所有的事将运行良好:
$ sudo pip install requests
password:
Downloading/unpacking requests
Running setup.py egg_info for package requests
Installing collected packages: requests Running setup.py install for requests
Successfully installed requests
Cleaning up ...
这次起作用了,我们能键入python并导入我们刚建立的新库:
>>>import requests
>>>requests.get('http://dabapp.com')
<Respomse[200]>
现在我们知道我们能导入requests并能在我们的程序中使用它。通过使用requests(可能还有许多其他来自PyPI的库)我们继续前进,心急火燎地工作开发出了新程序。这个软件工作起来超棒,我们赚了许多钱。也给客户留下了很好的印象,所以他们又要求我们写另外一个程序,这次事情稍微有点不同。
这次我们发现在requests中加入了一个全新的功能,由于在第二个程序中我们要用到第一个程序所以我们决定更新requests来得到新的功能:
$ sudo pip install --upgrade requests
看起来一切正常,但其实已经造成了一个大灾难!
在下次运行程序时,我们发现第一个程序(就是赚了大钱的那个)完全停止工作,当我们运行它时,它就抛出异常。这是怎么回事?因为与先前的版本相比,在我们刚更新的版本之中requests的API有些东西发生了变化。可这就意味我们的代码不再是使用正确的库了,我们的程序就垮掉了。
当然,我们能修改代码来使用新版本的requests API, 但那需要时间并会使我们从第二个程序中分心。另外,一位熟练的python程序员何止只有二个项目而是起码有一打。每个项目又会有几打的依赖库。保持它们都能更新并且与每个库的相同版本一起工作一定是个恶梦。
virtualenv怎样帮到我们?
virtualenv通过为你的每个程序建立一个完全隔离的虚拟环境来解决这个问题。一个虚拟环境简单的就是一个目录,包含了所有运行Python程序所需的软件,其中有一套编译为二进制码的可执行python拷贝,一套python标准库拷贝,一套pip拷贝,更为重要的是还有一套上面提到过的目录site-packages的拷贝。当你用由virtualenv工具所生成的pip从PyPI中安装包时,它就会将包安装到在你的虚拟环境目录中的site-packages中,在你的程序中你能象以前一样使用它们。
我怎样安装virtualenv?
如果你已经有了pip,最简单的方法是全局安装 sudo pip install virtualenv。通常只有pip和virtualenv两个包是需要全局安装的,因为一旦你有了这两个,其余的所有工作都能在虚拟环境中完成。
事实上,每一个你建造的新的环境,virtualenv都会拷贝一份自带的pip在其中,这样virtualenv就是你所需要的全部。你甚至能将其安装成为分开的脱机形式的包(不是来自PyPI)。对windows用户来说这可能更容易一些。
我如何创建一个新的虚拟环境?
你只需要virtualenv本身来创建一个新的虚拟环境。这真的很简单。从改变你的目录至你的项目的根目录开始,然后,用virtualenv命令行工具来创建一个新的环境:
$ cd ~/code/myproject/
$ virtualenv env`
New python executable in env/bin/python
Installing setuptools..........done.
Installing pip ...............done.
这里的env是你要创建的虚拟环境内一个目录的名字。通常将其约定命名为env,并放在你的项目根目录之下。假如你把你的代码放在~/code/projectname/,那么环境会在/code/projectname/env/中,每个项目都有自己的env。这只是约定,具体叫什么名字放在那里由你定。
注意:如果你在使用象git这样的版本控制系统,你不能提交env目录,可将其放入你的.gitignore文件中(或类似的文件)。
我如何使用我的簇新的虚拟环境?
如果进入你刚创建的env目录,你会看到一些子目录:
$ ls env
bin include lib
你最应关注的是bin。python和pip的本地拷贝就放在这里。现在,让我们用pip的拷贝来安装requests于虚拟环境之中(而不是全局)。
$ env/bin/pip install requests
Downloading/unpacking requests
Downloading requests-1.1.0.tar.gz (337kB) downloaded
Running setup.py egg_info for package requests
Installing collected packages: requests
Running setup.py install for requests
Successfully installed requests
Cleaning up...
它工作了! 注意这次我们没有使用sudo,因为没有对requests进行全局安装,而只是安装在我们的环境目录中。
现在,为了启动环境中的python交互式解释器,我们不是键入python,取而代之的是键入env/bin/python,
>>> import requests
>>>requests.get('http://dabapps.com')
<Response [200]>
但这要敲一大堆键
virtualenv在它的袖子里藏一个小花招,我们能运行一个脚本来激活环境,而不是每次都敲env/bin/python和env/bin/pip。
这个能与env/bin/activate一起运行的脚本只是简单地临时改动了几个系统变量名,这样当你键入python时,实际上运行的是在你的虚拟环境中的可执行的python二进制文件,而不是全局环境中的那个python。
现在我们运行pip install requests(取代了env/bin/pip install requests) 而且pip将把包安装在你的虚拟环境之中而不是在全局环境。这种对你的shell所作出的调整只能在你的终端始终处于开时持续有效,所以要记住,只要你关闭和重开终端窗口,就需要重新运行env/bin/activate。如果你需要转换到其他项目(他们各自有自己的环境),你可以运行deactivate来停上对一个环境的使用,并且在你转换到的项目环境中运行它的env/bin/activate来激活一个新的环境。
激活和停止环境的确节省的一些敲键但可能引起困惑,你自己决定是否使用它。
所需要的文件
virtualenv 和pip提供了许多方便,特别是当你使用pip的requirements功能时。你的每一个项目环境中都可有自己的requirements.txt文件,你能使用这种功能来安装项目需要的依赖库等到项目自己的虚拟环境中:
env/bin/pip install -r requirements.txt
具体细节请参考the pip document
总结
-
pip是python从PyPI中安装包的工具。
-
virtualenv工具是用来创建隔离的python环境,在其中含有python的可执行二进制代码文件和pip,并在自己的环境目录中保存从PyPI中安装的库。
-
它被设计用来使你可能在同一机器和同一时间来开发各自带有不同的依赖库的多个项目。你能从virtualenv.org中得到安装指导。
-
安装后,运行virtualenv env 就能创建一个新的名叫env的环境。
-
你的每个项目都需要各自的环境,注意不要让你的版本控制系统包含其中。
-
为了运行各自环境中的python和pip,要键入env/bin/python和env/bin/pip。
你能用env/bin/activate来激活一个环境,也能用env/bin/deactivate来停止一个环境。这完全是可选的,但可能会让生活变得容易一点。
pip和virtualenv对经常使用Python的开发者来说是不可或缺的。两者也相对简单。我们极力推荐掌握它们。
如果这篇博客启发了你学习python的兴趣,请你了解一下我们在Bighton DabApps HQ Python for Programmers研习班。
译后记
这篇博客链接在Bill Lubanovic所著的《PYTHON语言及其应用》一书附录D.3中。博客作者Jamie Matthews。本博客标题中的"非魔法式"一词表明作者的叙事方式,将pip和virtualenv的来龙去脉交待的非常清楚,不同于魔法式的介绍:凭空变出,而不说为什么。读后很有收获,想到可能还有其他人也需要学习了解,所以花了点时间将其译出,有错误请大家指出,我改正。