译者按:原文写于2011年末,虽然文中关于python 3的一些说法可以说已经不成立了,但是作为一篇面向从其他语言转型到python的程序员来说,本文对python的生态系统还是做了较为全面的介绍。文中提到了一些第三方库,但是python社区中强大的第三方库并不止这些,欢迎各位pytonistas补充。
•原文链接:http://mirnazim.org/writings/python-ecosystem-introduction/
•译文链接:http://codingpy.com/article/python-ecosystem-introduction/
开发者从php、ruby或其他语言转到python时,最常碰到的第一个障碍,就是缺乏对python生态系统的全面了解。开发者经常希望能有一个教程或是资源,向他们介绍如何以大致标准的方式完成大部分的任务。
本文中的内容,是对我所在公司内部维基百科的摘录,记录了面向网络应用开发的python生态系统基础知识,目标受众则是公司实习生、培训人员以及从其他语言转型到python的资深开发者。
文中所列的内容或资源是不完整的。我也打算把它当成一项一直在进行中的工作(work in perpetual progress)。希望经过不断的增补修订,本文会成为python生态系统方面的一篇详尽教程。
目标受众
本文的目的,不是教大家python编程语言。读完这篇教程,你也不会瞬间变成一名python高手。我假设大家已经有一定的python基础。如果你是初学者,那么别再继续读下去了。先去看看zed shaw所写的《笨办法学python》,这是本质量很高的免费电子书,看完之后再回头阅读这篇教程吧。
我假设你们使用的是linux(最好是ubuntu/debian)或是类linux操作系统。为什么?因为这是我最熟悉的系统。我在windows平台或mac os x平台上,没有专业的编程经验,只是测试过不同浏览器的兼容性。如果你用的是这两个平台,那么请参考下面的资料安装python。
python 101: setting up python on windows
official documentation for python on windows
official documentation for python on mac os x
你还可使用搜索引擎,查找你使用的操作系统中安装python的最好方法。如果你有什么疑问,我强烈建议你去stack overflow平台上提问。
该选择哪个版本?
python 2.x是目前的主流;python 3是崭新的未来。如果你不关心这个问题,可以直接跳到下面的python安装部分。(译者注:原文作者写这篇文章时是2011年,当时python 3才发展没几年。)
刚接触python的话,安装3.x版本看上去是很自然的第一步,但是这可能并不是你想要的。
目前有两个积极开发中的python版本——2.7.x与3.x(也被称为python 3, py3k和python 3000)。python 3是一个不同于python 2的语言。二者在语义、语法上,既存在细微的区别,又有着截然不同的一面。截至今天,python2.6/2.7是安装数量和使用度最高的版本。许多主流的python库、框架、工具都没有做到100%兼容python 3。
因此,最稳妥的选择就是使用2.x版(更准确的说,即2.7.x)。务必只在你需要或者完全了解情况的前提下,才选择python 3。
python 3 wall of shame网站记录了python 3对各种库的兼容情况。在使用python 3之前,仔细查阅下这个网站的内容。
译者注:现在,主流第三方库和框架对python 3的支持度已经很高。根据py3readiness网站的统计,360个最受欢迎的python包中已经有315个支持python 3。具体的支持情况,可以查看这个网站。一定程度上说,python 3已经成为新的主流。
使用哪种虚拟机
python的解释器,又叫做python虚拟机,它有多种不同的实现。其中,主流实现方式是cpython,装机量也最高,同时也是其他虚拟机的参考实现。
pypy是利用python语言实现的python;jython则使用java实现,并运行在java虚拟机之上;ironpython是用.net clr实现的python。
除非真的有重大理由,否则应该选择cpython版本的实现,避免出现意外情况。
如果这些有关版本和虚拟机的唠叨话让你读了头疼,那你只需要使用cpython 2.7.x即可。
python安装
大部分linux/unix发行版和mac os x都预装了python。如果你没有安装或者已有的版本比较旧,那么你可以通过下面的命令安装2.7.x版:
ubuntu/debian及其衍生系统
代码如下:
$ sudo apt-get install python2.7
sudo是类unix系统中的一个程序,可以让用户以其他用户的权限(通常是超级用户或root用户)运行程序。
fedora/red hat及类似系统
sudo yum install python2.7
在rhel(red hat enterprise linux的缩写)平台上,你可能需要启用epel软件源(repositories),才能正常安装。
在本文后面的示例中,我会使用sudo程序;你应将其替换为自己版本中的相应命令或程序。
理解python的包(package)
首先你需要了解的是,python没有默认的包管理工具。事实上,python语言中包的概念,也是十分松散的。
你可能也知道,python代码按照模块(module)划分。一个模块,可以是只有一个函数的单个文件,也可以是包含一个或多个子模块的文件夹。包与模块之间的区别非常小,每个模块同时也可以视作一个包。
那么模块与包之间,到底有什么区别?要想解答这个问题,你首先要了解python是如何查找模块的。
与其他编程环境类似,python中也有一些函数和类(比如str,len和exception)是存在于全局作用域(global scope,在python中被称为builtin scope)的,其他的函数和类则需要通过import语句进行引用。例如:
代码如下:
>>> import os
>>> from os.path import basename, dirname
这些包就在你的文件系统中的某处,所以能被import语句发现。那么python是怎么知道这些模块的地址?原来,在你安装python虚拟机的时候,就自动设置了这些地址。当然平台不同,这些地址也就不一样。
你可以通过sys.path查看系统中的包路径。这是我的笔记本运行该命令之后的输出结果,系统是ubuntu 11.10 oneric ocelot。
>>> import sys
>>> print sys.path
[”,
‘/usr/lib/python2.7’,
‘/usr/lib/python2.7/plat-linux2’,
‘/usr/lib/python2.7/lib-tk’,
‘/usr/lib/python2.7/lib-old’,
‘/usr/lib/python2.7/lib-dynload’,
‘/usr/local/lib/python2.7/dist-packages’,
‘/usr/lib/python2.7/dist-packages’,
‘/usr/lib/python2.7/dist-packages/pil’,
‘/usr/lib/python2.7/dist-packages/gst-0.10’,
‘/usr/lib/python2.7/dist-packages/gtk-2.0’,
‘/usr/lib/pymodules/python2.7’,
‘/usr/lib/python2.7/dist-packages/ubuntu-sso-client’,
‘/usr/lib/python2.7/dist-packages/ubuntuone-client’,
‘/usr/lib/python2.7/dist-packages/ubuntuone-control-panel’,
‘/usr/lib/python2.7/dist-packages/ubuntuone-couch’,
‘/usr/lib/python2.7/dist-packages/ubuntuone-installer’,
‘/usr/lib/python2.7/dist-packages/ubuntuone-storage-protocol’]
这行代码会告诉你python搜索指定包的所有路径,这个路径就存储在一个python列表数据类型中。它会先从第一个路径开始,一直往下检索,直到找到匹配的路径名。这意味着,如果两个不同的文件夹中包含了两个同名的包,那么包检索将会返回其遇到的第一个绝对匹配地址,不会再继续检索下去。
你现在可能也猜到了,我们可以轻松地修改(hack)包检索路径,做到你指定的包第一个被发现。你只需要运行下面的代码:
>>> sys.path.insert(0, ‘/path/to/my/packages’)
尽管这种做法在很多情况下十分有用,但是你必须牢记sys.path很容易被滥用。务必在必要时才使用这种方法,并且不要滥用。
site模块控制着包检索路径设置的方法。每次python虚拟机初始化时,就会被自动引用。如果你想更详细地了解整个过程,可以查阅官方文档。
pythonpath环境变量
pythonpath是一个可以用来增强默认包检索路径的环境变量。可以把它看作是一个path变量,但是一个只针对python的变量。它只是一些包含有python模块的文件路径列表(不是sys.path所返回的python列表),每个路径之间以:分隔。设置方法很简单,如下:
代码如下:
export pythonpath=/path/to/some/directory:/path/to/another/directory:/path/to/yet/another/directory
在某些情况下,你不用覆盖已有的pythonpath,只需要在开头或结尾加上新的路径即可。
代码如下:
export pythonpath=$pythonpath:/path/to/some/directory # append
export pythonpath=/path/to/some/directory:$pythonpath # prepend
pythonpath、sys.path.insert`和其他类似的方法,都是hack小技巧,一般情况下最好不要使用。如果它们能够解决本地开发环境出现的问题,可以使用,但是你的生产环境中不应该依赖这些技巧。要取得同样的效果,我们还可以找到更加优雅的方法,稍后我会详细介绍。
现在你明白了python如何查找已安装的包,我们就可以回到一开始的那个问题了。python中,模块和包的区别到底是什么?包就是一个或多个模块/子模块的集合,一般都是以经过压缩的tarball文件形式传输,这个文件中包含了:1. 依赖情况(如果有的话);2.将文件复制到标准的包检索路径的说明;3. 编译说明——如果文件中包含了必须要经过编译才能安装的代码。就是这点区别。
第三方包(third party packages)
如果想利用python进行真正的编程工作,你从一开始就需要根据不同的任务安装第三方包。
在linux系统上,至少有3种安装第三方包的方法。
使用系统本身自带的包管理器(deb, rpm等)
通过社区开发的类似pip, easy_install等多种工具
从源文件安装
这三种方法做的几乎是同一件事情,即安装依赖包,视情况编译代码,然后把包中模块复制到标准包检索路径。
尽管第二种和第三种方法在所有操作系统中的实现都一致,我还是要再次建议你查阅stack overflow网站的问答,找到你所使用系统中其他安装第三方包的方法。
去哪找第三方包?
在安装第三方包之前,你得先找到它们。查找包的方法有很多。
你使用的系统自带的包管理器
python包索引(也被称为pypi)
各种源码托管服务,如launchpad, github, bitbucket等。
通过系统自带的包管理器安装
使用系统自带的包管理器安装,只需要在命令行输入相应命令,或是使用你用来安装其他应用的gui应用即可。举个例子,要在ubuntu系统上安装simplejson(一个json解析工具),你可以输入下面的命令:
$ sudo apt-get install python-simplejson
通过pip安装
easy_install已经不太受开发者欢迎。本文将重点介绍easy_install的替代者——pip。
pip是一个用来安装和管理python包的工具。它并不是一个python虚拟机自带的模块,所以我们需要先安装。在linux系统中,我一般会这样操作:
$ sudo apt-get install python-pip
在安装其他包之前,我总是会把pip升级到pypi中的最新版本,因为ubuntu默认源中的版本比pypi的低。我这样升级pip。
$ sudo pip install pip –upgrade
现在,你可以通过运行run pip install package-name,安装任何python包。所以,要安装simplejson的话,你可以运行以下命令:
$ sudo pip install simplejson
移除包也一样简单。
$ sudo pip uninstall simplejson
pip默认会安装pypi上最新的稳定版,但是很多时候,你会希望安装指定版本的包,因为你的项目依赖那个特定的版本。要想指定包的版本,你可以这样做:
$ sudo pip install simplejson==2.2.1
你还会经常需要升级、降级或者重装一些包。你可以通过下面的命令实现:
$ sudo pip install simplejson –upgrade # upgrade a package to the latest version from pypi
$ sudo pip install simplejson==2.2.1 –upgrade # upgrade/downgrade a package to a given version
接下来,假设你想安装某个包的开发版本,但是代码没有放在pypi上,而是在版本控制仓库中,你该怎么办?pip也可以满足这个需求,但是在此之前,你需要在系统上安装相应的版本控制系统(vcs)。在ubuntu平台,你可以输入下面的命令:
$ sudo apt-get install git-core mercurial subversion
安装好vcs之后,你可以通过下面的方式从远程仓库中安装一个包:
代码如下:
$ sudo pip install git+http://hostname_or_ip/path/to/git-repo#egg=packagename
$ sudo pip install hg+http://hostname_or_ip/path/to/hg-repo#egg=packagename
$ sudo pip install svn+http://hostname_or_ip/path/to/svn-repo#egg=packagename
从本地仓库中安装也同样简单。注意下面文件系统路径部分的三个斜杠(///)。
$ sudo pip install git+file:///path/to/local/repository
通过git协议安装时,请注意,你要像下面这样使用git+git前缀:
$ sudo pip install git+git://hostname_or_ip/path/to/git-repo#egg=packagename
现在,你可能在纳闷这些命令中的eggs是什么东西?目前你只需要知道,一个egg就是经zip压缩之后的python包,其中包含了包的源代码和一些元数据。pip在安装某个包之前,会构建相关的egg信息。你可以打开代码仓库中的setup.py文件,查看egg的名字(几乎都会注明)。找到setup部分,然后看看有没有一行类似name=”something”的代码。你找到的代码可能会和下面这段代码类似(来自simplejson包中的setup.py文件)。
setup(
name=”simplejson”, # >> import this
the zen of python, by tim peters
beautiful is better than ugly.
explicit is better than implicit.
simple is better than complex.
complex is better than complicated.
flat is better than nested.
sparse is better than dense.
readability counts.
special cases aren’t special enough to break the rules.
although practicality beats purity.
errors should never pass silently.
unless explicitly silenced.
in the face of ambiguity, refuse the temptation to guess.
there should be one– and preferably only one –obvious way to do it.
although that way may not be obvious at first unless you’re dutch.
now is better than never.
although never is often better than *right* now.
if the implementation is hard to explain, it’s a bad idea.
if the implementation is easy to explain, it may be a good idea.
namespaces are one honking great idea — let’s do more of those!