在这里我假设你已经看完了一篇Python教程,基本熟悉了Python的结构和语法,在命令行下的Python互动环境中尝试过大部分Python的语句,觉得Python是个不错的语言准备继续下去。那么本篇文章会就Python实际运用中相关工具的选择,包括IDE,调试套件,第三方库管理工具这些进行介绍。另外还会对某些中文环境下容易遇到的问题,例如unicode编码解码的问题进行说明。本文主要是针对 Windows 环境下的 Python 开发进行说明。文章的目的是为了分享些我觉得很有用的经验和例子,若发现文中有疏漏之处请务必联系我。谢谢。
Python 语言介绍
Python 是一个近些年在开始流行起来的计算机编程语言。根据Python官网上的简介,Python主要特性包括跨平台,免费,简单且容易维护。就我个人理解来说,Python是一门适合大部分人的语言,因为各种类型的第三方库都有,所以像简单桌面程序,动态网站开发,图像处理,表格处理,甚至自动发帖机这些小应用在简单的学习后,不需要很深厚的编程经验的人应该都能自己做出来。
Python 版本选择,其他发行版
Python 2 与 3
Python 2 和 3 系列的选择可能是比较让人烦躁的事情。其实区别很简单:Python 3.x 各个方面都更好,但语法与 Python 2.x 很大部分不兼容。Python 2.x 已经停止继续开发。但是目前很多第三方库仍然不支持 Python 3 , 文章后面介绍的很多工具譬如 ipython 目前也是仅支持 Python 2.6 的。
我建议现在选择 Python 2.6.5 ,因为目前大部分第三方库和工具对2.6都有简单的安装包,不需要自己做太多处理。
发行版
目前在 Windows 下除了官方提供的安装版外,还有:
ActivePython ,这个与官方版本的区别在于提供了额外的库和文档,并且自动设置了PATH环境变量(后文会详细提到)
Python(x,y),这个是我一直用并且推荐给别人用的版本。从名字就能看出来这个发行版附带了科学计算方面的很多常用库,另外还有大量常用库比如用于桌面软件界面制作的 PyQt, 还有文档处理,exe文件生成等常用库。另外的还有大量的工具如IDE,制图制表工具,加强的互动shell之类。很多下文提到的软件在此发行版中都有附带。其他方面,Python(x, y)还附带了手工整理出的所有库的离线文档,每个小版本升级都提供单独的补丁。总的来说是很用心维护的一个发行版,十分建议安装这个版本。
开发相关工具
在真正着手开发之前,你应该在下载一份离线的文档。在这个页面下载一份 HTML 格式的,解压出来其中 index.html 就是文档主页面。页面左边的 Quick Search 是离线也可以使用的,有对函数功能有疑惑或者要查询模块的时候就能在这里查看。
选择 PyDev 作为 IDE
Python 集成开发环境的选择好像一直以来也是一个很难抉择的问题。在尝试过很多个工具后我发现基于 Eclipse 的 PyDev 绝对是功能最为完整的一个 IDE 。除了断点调试之外,PyDev 的代码自动补全可能是现在这类 IDE 中最强力的。
如果你安装了 Python(x, y) 的话,PyDev 就已经在你的机器上了。如果没有的话请按照这篇文章来进行安装。
设置上有一些需要注意的地方。首先在打开 PyDev ,打开菜单中
Window -> Preferences
,在弹出对话框中左边找到
PyDev -> Editor -> Code Completion
。这里可以设置代码自动补全的相关信息。可以降低 Autocompletion delay 来更早的提示代码,并且将 Request completion on 系列尽可能勾上,让 PyDev尽可多的提示代码。
Window -> Preferences
,在弹出对话框中左边找到
PyDev -> Editor -> Code Completion
。这里可以设置代码自动补全的相关信息。可以降低 Autocompletion delay 来更早的提示代码,并且将 Request completion on 系列尽可能勾上,让 PyDev尽可多的提示代码。
之后再找到
Interpreter Python
选项卡,这里可以设置所谓 Forced Buildins,可以强制引入某些第三方库从而完成代码补全。就我的经验来看大部分第三方库在这样设置后都能进行基本的补全。具体的做如图中,选择到对应的选项卡,点击 New,并输入你需要的模块名字即可。
Interpreter Python
选项卡,这里可以设置所谓 Forced Buildins,可以强制引入某些第三方库从而完成代码补全。就我的经验来看大部分第三方库在这样设置后都能进行基本的补全。具体的做如图中,选择到对应的选项卡,点击 New,并输入你需要的模块名字即可。
设置后总体效果绝对是同类IDE中比较好的:
IPython 替代 Python Shell
在学习 Python 的时候应该都接触过 Python 的 Shell,能够输入 Python 语句并且立即返回结果。而 IPython就是一个豪华加强版的 Python Shell。如果你安装了 Python(x, y) 的话,那 IPython 已经在你的机器上了。如果没有的话那么请在这里下载 Windows Installer 进行安装。在安装这个之后还需要安装 pyreadline 让 IPython 开启高亮和自动补全功能。之后你在命令行下需要 python 的时候改为输入 ipython就能使用它了。开启 IPython 看看,首先感觉的不同应该是这个是有颜色的。我们来看看它提供的一些基础而实用的功能吧。首先是自动补全,一种是简单的关键字补全,另外一种是对象的方法和属性补全。作为例子,我们先引入sys模块,之后再输入 sys.(注意有个点),此时按下 tab 键,IPython 会列出所有 sys 模块下的方法和属性。因为是在互动模式下进行的,此时的 Python 语句实实在在的被执行了,所以对普通 object 的补全也是很完好的。
接着上面的例子,我们输入sys?,这样会显示出sys模块的 docstring及相关信息。很多时候这个也是很方便的功能。
IPython 另外还有很多方便的功能,可以自己参阅文档来发掘。这里另外介绍一个很神奇的功能。如果你的程序是由命令行开始执行的,即在命令行下输入python foo.py
(大部分 Python 程序都是),那么你还可以利用 IPython 在你的程序任意地方进行断点调试!在你程序中任意地方,加入如下语句:
(大部分 Python 程序都是),那么你还可以利用 IPython 在你的程序任意地方进行断点调试!在你程序中任意地方,加入如下语句:
from IPython.Shell import IPShellEmbed IPShellEmbed([])()
再和平常一样运行你的程序,你会发现在程序运行到插入语句的地方时,会转到 IPython 环境下。你可以试试运行些指令,就会发现此刻 IPython 的环境就是在程序的那个位置。你可以逐个浏览当前状态下的各个变量,调用各种函数,输出你感兴趣的值来帮助调试。之后你可以照常退出 IPython,然后程序会继续运行下去,自然地你在当时 IPython 下执行的语句也会对程序接下来的运行造成影响。
这个方法我实在这里看到的。想象一下,这样做就像让高速运转的程序暂停下来,你再对运行中的程序进行检查和修改,之后再让他继续运行下去。这里举一个例子,比如编写网页 bot ,你在每取回一个页面后你都得看看它的内容,再尝试如何处理他获得下一个页面的地址。运用这个技巧,你可以在取回页面后让程序中断,再那里实验各种处理方法,在找到正确的处理方式后写回到你的代码中,再进行下一步。这种工作流程只有像 Python 这种动态语言才可以做到。
pip 管理第三方库
Python 的一大优势就是有极为大量的第三方库,包括各个方面的引用。然而安装第三方库对没有掌握方法的同学来说会变得很让人烦恼。事实上 Python 第三方库的安装和管理有着一个一个唯一正确的做法,这个做法要求你什么其他的都不用干,只要输入你要安装库的名字就可以了。
setuptools 也包在 Python(x, y) 当中。如果没有的话,要首先先安装 setuptools ,这个其实就是一个安装第三方库的软件。选择对应版本的 Windows Installer 进行下载和安装后,打开一个命令行窗口,输入:
easy_install pip
如果提示找不到程序,那么说明你当前没有设定好环境变量。安装官方提供的 Python 安装包的话肯定会有这个问题,而且很可能暂时不会修正,这就是牛逼程序员的倔强。具体做法是 右键我的电脑 - 属性 - 高级系统设置 - 环境变量 - 将
C:\python2*\Scripts
加入到 PATH 那一组当中。这样做的效果就是在任何地方的命令行下输入命令,那么系统会额外查找我们设定的那个目录中的内容。之后再执行上面的命令,装好了以后我们就要弃用 setuptools,转投 pip。要安装任何一个库,你只要找到他的名字(不需要版本号),用 pip 安装即可。譬如安装 django,那么输入如下命令即可:
C:\python2*\Scripts
加入到 PATH 那一组当中。这样做的效果就是在任何地方的命令行下输入命令,那么系统会额外查找我们设定的那个目录中的内容。之后再执行上面的命令,装好了以后我们就要弃用 setuptools,转投 pip。要安装任何一个库,你只要找到他的名字(不需要版本号),用 pip 安装即可。譬如安装 django,那么输入如下命令即可:
pip install django
其实之前easy_install跟 pip效用是类似的,都是在官方的第三方库索引 PyPI 查询信息并进行下载和安装。pip 的优势在于支持更高级的功能,譬如虚拟环境,安装失败不会残留破损的库,更重要的是 pip 还可以进行卸载。输入下面命令就能卸载一个之前由 pip 进行安装的库。继续上面的例子,现在要卸载 django:
pip uninstall django
这是 setuptools 所缺失的功能。需要额外说明的是大部分纯 Python 的库都能用这个方法在 Windows 下装上,但是需要编译 C 语言模块的一般都不太可能成功。遇到这种情况,在相应的库德站点上找找有没有对应的 Windows 安装包。
Winpdb
如果你使用的 PyDev 的话那么用其自带的断点调试应该就可以了。Winpdb则是为用其他简单编辑器进行 Python 开发的用户提供一个熟悉的调试环境。Winpdb不出意料的也在 Python(x, y)当中。所以如果装上 Python(x, y) 你可以不断发掘里面附带的优秀工具。使用方法很简单,假设程序名为 foo.py,那么在命令行中输入:
winpdb foo.py
之后会弹出窗口,也就是一个大家都熟悉的 debug 图形界面。需要注意的是这里需要点击想要设置断点的行,点击 F9 设置断点,然后该行底色会变为红色,如下图所示。
编码问题
作为中文用户,初学 Python 最容易碰到的问题估计就是编码问题了。明明英文的都可以用到中文的时候就要出问题,而且出错信息难以理解,想要解决问题又不知道从何开始。幸运的是编码问题通过预防性的措施是很好避免的。下面从几个方面来讲讲 Python 中处理中文及 Unicode 容易碰到的问题。
Unicode 编码基础
这里非常简单的讲一下编码知识,此部分表述可能不太准确,如果你对 Unicode 更为了解的话请联系我帮忙纠正。
你可以想象 Unicode 是一个很大的表,里面有着世界上所有的文字的个体,如英文中的字母,中文的汉字。事实上 Unicode 标准中每一个字都有一个唯一对应的编号,好比说 '中'字 对应十六进制 0x4E2D,而字母 'a' 对应的是十六进制 0x0061。这个编号是由 Unicode Consortium 这个组织来确定的。 如果说用这个编码来对应字符来用于表示字符,理论上是可以的,这样的话就是每一个数字编号能对应一个字符。
而实际情况中,不是每篇文章都用得到世界上所有的字符。譬如一篇英文文章就只有英文字母加上一些符号,用 Unicode 来进行存储的话每个字符要浪费太多的空间。所以就有各种类型的编码产生。编码我们这里可以理解就是将一部分的 Unicode (比如说所有的中文,或者所有的日文)字符,以某种方式确定另外一个符号来代表他。中文常用编码有 UTF8 和 GBK,仍然以 '中'字 为例, UTF8 编码将对应 '中'字 的 Unicode 编号
0x4E2D
拆成三个的编号的组合,
[0xE4, 0xB8, 0xAD]
,只有这几个连在一起的时候才会被作为一个 '中'字 显示出来;作为对比,GBK 编码将 '中'字 对应的 Unicode 编号
0x4E2D
编码成为两个编号的组合
[0xD6, 0xD0]
,在 GBK 编码环境下只有这两个编号一起时,才会显示为 '中'字。
0x4E2D
拆成三个的编号的组合,
[0xE4, 0xB8, 0xAD]
,只有这几个连在一起的时候才会被作为一个 '中'字 显示出来;作为对比,GBK 编码将 '中'字 对应的 Unicode 编号
0x4E2D
编码成为两个编号的组合
[0xD6, 0xD0]
,在 GBK 编码环境下只有这两个编号一起时,才会显示为 '中'字。
上面的例子中,如果把 UTF8 编码后的
[0xE4, 0xB8, 0xAD]
放到 GBK 环境下来显示会怎样?这几个编号跟 '中'字 在 GBK 下的编码
[0xD6, 0xD0]
,不同,则显然不会显示为 '中'字。这三个字符会跟排在其前后的字符一起,按照 GBK 的编码规则找有没有对应的字符。结果有可能显示出一个毫不相关的字符,有时候为符号或者干脆不显示,这种情况就算产生了乱码。
[0xE4, 0xB8, 0xAD]
放到 GBK 环境下来显示会怎样?这几个编号跟 '中'字 在 GBK 下的编码
[0xD6, 0xD0]
,不同,则显然不会显示为 '中'字。这三个字符会跟排在其前后的字符一起,按照 GBK 的编码规则找有没有对应的字符。结果有可能显示出一个毫不相关的字符,有时候为符号或者干脆不显示,这种情况就算产生了乱码。
Python 2.x 中的 String 与 Unicode
在 Python 2.x 中是有两种字串符相关类型的,分别为 String 和 Unicode,两者提供的接口非常类似,有时候又能自动转换,蛮容易误导人的。在 Python 3 中 这两个类型分别用 Bytes 和 String 替代了。这个名字更能说明两者的本质:Python 2.x 中的 String 中存储的是没有编码信息的字节序列,也就是说 String 中存储的是已经编码过后的序列,但他并不知道自身是用的哪种编码。相反的 Unicode 中存储的是记载了编码的字串信息,其中存储的就是相应字符的 Unicode 编号。在这里用程序来说明,我们建立一个简单的脚本名字为
encoding.py
,代码如下:
encoding.py
,代码如下:
#!/usr/bin/python # -*- coding: utf-8 -*- strs = "这是中文" unis = "这也是中文".decode("utf8") print strs[0:2] print unis[0:2].encode('gbk') print len(strs) print len(unis) 前面两行后面会解释到,就是限定运行环境以及该脚本文件的编码格式。此脚本在这里可以下载,如果你要自己写的话请务必确保脚本的编码是 utf8 而不是别的。在 Windows 下的运行结果在这里,我觉得正好能说明问题:
C:\SHARED\Dev\scripts>encoding.py 杩 这也 12 5
这里需要说明,我们的程序是 UTF8 编码,主要意义是该程序中的所有直接写出来的字串符(用"", ''括起来的字串符)是运用 UTF8 格式编码的;然而 Windows 下的命令行是 GBK 环境。这里strs是一个 String。事实上在 Python 2.x 中直接写在程序中的字串符,其类型都是
String(这里不考虑 string literal)。我们先直接输出 strs[0:2],得到的是一个乱码字符(这个字符只是碰巧凑成是一个字)。如上面说的,String中存储的是没有编码信息的字串序列,这里就是将
strs中前两个编号取出并尝试显示。由于命令行环境为 GBK 编码,这里对应的字碰巧凑成了一个字,但是跟原本的字没有任何关系。unis是由一个String调用decode()方法得到,这正是在 Python 2.x 中取得Unicode的最基本的方式。由于String并不知道它本身是由什么编码格式来进行的编码,这里是我们的责任来确定他原来是用哪种编码方式进行编码。我们知道代码中的编码格式是 UTF8,所以我们可以用调用String的 decode()方法来进行反编码,也就是解码, 把字串符从某种编码后的格式转换为其唯一对应的 Unicode 编号。unis为解码获得的结果,其在 Python 2.x 中对应类型就是Unicode,其中存储的就是 每个字符对应的 Unicode 编号。我们尝试输出unis的前两个字符,在这里我们调用了Unicode的 encode()方法。这就是编码的过程。我们知道 Windows 命令行下的编码是 GBK,只有采用 GBK 编码的字符才能正确显示。所以在这里我们通过调用Unicode的encode()方法,将 unis中存储的 Unicode 编号 按照 GBK 的规则来进行编码,并输出到屏幕上。这里我们看到这里正确的显示了unis中的前两个字符。要注意的是在命令行中直接printUnicode的话 Python 会自动根据当前环境进行编码后再显示,但这样掩盖了两者的区别。建议总是手动调用encode和 decode方法,这样自己也会清楚一些。后面两者长度的差别也是佐证我们之前的例子。
String(这里不考虑 string literal)。我们先直接输出 strs[0:2],得到的是一个乱码字符(这个字符只是碰巧凑成是一个字)。如上面说的,String中存储的是没有编码信息的字串序列,这里就是将
strs中前两个编号取出并尝试显示。由于命令行环境为 GBK 编码,这里对应的字碰巧凑成了一个字,但是跟原本的字没有任何关系。unis是由一个String调用decode()方法得到,这正是在 Python 2.x 中取得Unicode的最基本的方式。由于String并不知道它本身是由什么编码格式来进行的编码,这里是我们的责任来确定他原来是用哪种编码方式进行编码。我们知道代码中的编码格式是 UTF8,所以我们可以用调用String的 decode()方法来进行反编码,也就是解码, 把字串符从某种编码后的格式转换为其唯一对应的 Unicode 编号。unis为解码获得的结果,其在 Python 2.x 中对应类型就是Unicode,其中存储的就是 每个字符对应的 Unicode 编号。我们尝试输出unis的前两个字符,在这里我们调用了Unicode的 encode()方法。这就是编码的过程。我们知道 Windows 命令行下的编码是 GBK,只有采用 GBK 编码的字符才能正确显示。所以在这里我们通过调用Unicode的encode()方法,将 unis中存储的 Unicode 编号 按照 GBK 的规则来进行编码,并输出到屏幕上。这里我们看到这里正确的显示了unis中的前两个字符。要注意的是在命令行中直接printUnicode的话 Python 会自动根据当前环境进行编码后再显示,但这样掩盖了两者的区别。建议总是手动调用encode和 decode方法,这样自己也会清楚一些。后面两者长度的差别也是佐证我们之前的例子。
strs中存储的是 UTF8 编码后的编号序列,上面看到一个中文字符在 UTF8 编码后变成三个连续的,所以 strs长度为 3x4 = 12。你可以想象 strs中存放的并不是中文,而是一系列没有意义的比特序列;而unis中存储的是对应的中文的 Unicode 编码。我们知道每一个字符对应一个编号,所以五个字对应五个编号,长度为 5。
避免,和解决编码产生的问题
了解了 Python Unicode 编码解码的这些概念后,我们来看看如何尽量的避免遇到让人烦心的编码问题。
首先如果你的代码中有中文,那么一定要务必声明代码的编码格式。根据 PEP-0263 中的介绍,在程序的最开始加上以下两行注释就能确定编码:
#!/usr/bin/python # -*- coding: utf-8 -*-
其中utf-8就是指定的编码格式。事实上你应该总是使用 UTF8 作为你 Python 程序的编码格式,因为未来的 Python 3 所有文件都将默认以 UTF8 编码。另外除了声明,你必须确定你用来编辑 Python 程序的编辑器是不是真的以 UTF8 编码来存储文件。
之后就是养成关于编码解码的好习惯。当你的程序有 String作为输入时,应该尽早的将其转换为 Unicode,再在程序中进行处理。再输出的时候,也要尽可能玩,直到最后输出的时刻才将 Unicode编码为所需编码格式的 String进行输出。同样的你必须保持你程序内部所有参与运算的字串都是 Unicode格式。很多著名的 Python 库例如 django 就是采用的这种方式,效果也蛮好。千万不要依赖 Python 自己进行两者之间的转换,也不要将 String和 Unicode放在一起运算,这些行为一方面十分容易引起错误,另一方面在 Python 3 中已经无法再现。虽说确定 String的编码格式是程序员的责任,但有时候你真的不知道有些字串符到底是什么编码的。这里有一个神奇 chardet 能够帮助你。以下是摘自其页面上的例子,很好了说明了它的作用:读入任意一串字符,猜测其编码格式,并且给出猜测的确信度。
>>> import urllib >>> urlread = lambda url: urllib.urlopen(url).read() >>> import chardet >>> chardet.detect(urlread("http://google.cn/")) {'encoding': 'GB2312', 'confidence': 0.99} >>> chardet.detect(urlread("http://yahoo.co.jp/")) {'encoding': 'EUC-JP', 'confidence': 0.99} >>> chardet.detect(urlread("http://amazon.co.jp/")) {'encoding': 'SHIFT_JIS', 'confidence': 1} >>> chardet.detect(urlread("http://pravda.ru/")) {'encoding': 'windows-1251', 'confidence': 0.9355} 如果 confidence 非常低的话或者 chardet 直接报错,多半是字串经过多次错误编码解码,要从别的地方找办法解决问题。
如果上面的介绍还不能让你理解 Unicode 的概念,这里还有几篇关于这个问题的文章:
Unicode In Python, Completely Demystified 特别针对 Python 下的 Unicode 处理进行详细的讲解。
No comments:
Post a Comment