(這是很早之前寫的但內(nèi)容沒(méi)有太過(guò)時(shí),發(fā)到這邊補(bǔ)全一下...)
面向初學(xué)者介紹Python相關(guān)的一些工具,以及可能遇到的常見(jiàn)問(wèn)題。
引言
在這里我假設(shè)你已經(jīng)看完了一篇Python教程,基本熟悉了Python的結(jié)構(gòu)和語(yǔ)法,在命令行下的Python互動(dòng)環(huán)境中嘗試過(guò)大部分Python的語(yǔ)句,覺(jué)得Python是個(gè)不錯(cuò)的語(yǔ)言準(zhǔn)備繼續(xù)下去。那么本篇文章會(huì)就Python實(shí)際運(yùn)用中相關(guān)工具的選擇,包括IDE,調(diào)試套件,第三方庫(kù)管理工具這些進(jìn)行介紹。另外還會(huì)對(duì)某些中文環(huán)境下容易遇到的問(wèn)題,例如unicode編碼解碼的問(wèn)題進(jìn)行說(shuō)明。本文主要是針對(duì) Windows 環(huán)境下的 Python 開(kāi)發(fā)進(jìn)行說(shuō)明。文章的目的是為了分享些我覺(jué)得很有用的經(jīng)驗(yàn)和例子,若發(fā)現(xiàn)文中有疏漏之處請(qǐng)務(wù)必聯(lián)系我。謝謝。
Python 語(yǔ)言介紹
Python 是一個(gè)近些年在開(kāi)始流行起來(lái)的計(jì)算機(jī)編程語(yǔ)言。根據(jù)Python官網(wǎng)上的簡(jiǎn)介,Python主要特性包括跨平臺(tái),免費(fèi),簡(jiǎn)單且容易維護(hù)。就我個(gè)人理解來(lái)說(shuō),Python是一門適合大部分人的語(yǔ)言,因?yàn)楦鞣N類型的第三方庫(kù)都有,所以像簡(jiǎn)單桌面程序,動(dòng)態(tài)網(wǎng)站開(kāi)發(fā),圖像處理,表格處理,甚至自動(dòng)發(fā)帖機(jī)這些小應(yīng)用在簡(jiǎn)單的學(xué)習(xí)后,不需要很深厚的編程經(jīng)驗(yàn)的人應(yīng)該都能自己做出來(lái)。
一些流行的Python教程有:
Dive into Python 面向有一定編程基礎(chǔ)的同學(xué)。另外還有Dive into Python 3,針對(duì)Python3的教程。
Learn Python The Hard Way,書中主要是通過(guò)各種練習(xí)來(lái)進(jìn)行學(xué)習(xí),面向完全沒(méi)有編程經(jīng)驗(yàn)的同學(xué)。
Invent Your Own Computer Game With Python,讓你一上手就做個(gè)游戲出來(lái)的教程,厲害吧。
The Python Tutorial,官方文檔中的教程,正統(tǒng)而完整。
如果你還沒(méi)有開(kāi)始接觸 Python ,或者覺(jué)得還不夠熟悉,那么不妨找一份你覺(jué)得看得下去的教程開(kāi)始學(xué)習(xí)吧。就我個(gè)人經(jīng)驗(yàn)來(lái)說(shuō),Python 是我到目前為止覺(jué)得學(xué)的最劃得來(lái)的一門語(yǔ)言,也是日常用的最多的一門,而事實(shí)上你并不需要了解完全了解 Python 就能在開(kāi)始使用它。
Python 版本選擇,其他發(fā)行版
Python 2 與 3
Python 2 和 3 系列的選擇可能是比較讓人煩躁的事情。其實(shí)區(qū)別很簡(jiǎn)單:Python 3.x 各個(gè)方面都更好,但語(yǔ)法與 Python 2.x 很大部分不兼容。Python 2.x 已經(jīng)停止繼續(xù)開(kāi)發(fā)。但是目前很多第三方庫(kù)仍然不支持 Python 3 , 文章后面介紹的很多工具,特別是科學(xué)計(jì)算的庫(kù)仍然只支持 Python 2.x。
原來(lái)這里寫的推薦版本是 2.6,現(xiàn)在的情況是 2.7 版本是 2.x 系列最后一個(gè)大版本號(hào),以后只會(huì)有 2.7.x 的維護(hù)版本并不再會(huì)添加新功能。Python 3 現(xiàn)在已經(jīng)足夠成熟,很多常見(jiàn)的庫(kù)都已經(jīng)移植到 Python 3 上了。所以現(xiàn)在如果你是自己學(xué) Python 那么上來(lái)直接 Python 3 沒(méi)啥問(wèn)題,但如果你是在工作的地方或者對(duì)科學(xué)計(jì)算有要求那么還是需要 Python 2.7 比較好。
這里我發(fā)現(xiàn)有一個(gè)比較靠譜的選擇辦法,就是看 Python(x,y) 帶的 Python 版本。它現(xiàn)在還是在 2.7,這個(gè)版本基本上所有的第三方庫(kù)都在支持。當(dāng)哪一天 Python(x,y) 上到 Python 3 了那估計(jì)就是可以安心用 Python 3 的時(shí)候了。但按現(xiàn)在這個(gè)情況估計(jì)還得好幾年吧。
發(fā)行版
目前在 Windows 下除了官方提供的安裝版外,還有:
ActivePython ,這個(gè)與官方版本的區(qū)別在于提供了額外的庫(kù)和文檔,并且自動(dòng)設(shè)置了PATH環(huán)境變量(后文會(huì)詳細(xì)提到)
Python(x,y),這個(gè)是我一直用并且推薦給別人用的版本。從名字就能看出來(lái)這個(gè)發(fā)行版附帶了科學(xué)計(jì)算方面的很多常用庫(kù),另外還有大量常用庫(kù)比如用于桌面軟件界面制作的 PyQt, 還有文檔處理,exe文件生成等常用庫(kù)。另外的還有大量的工具如IDE,制圖制表工具,加強(qiáng)的互動(dòng)shell之類。很多下文提到的軟件在此發(fā)行版中都有附帶。其他方面,Python(x, y)還附帶了手工整理出的所有庫(kù)的離線文檔,每個(gè)小版本升級(jí)都提供單獨(dú)的補(bǔ)丁??偟膩?lái)說(shuō)是很用心維護(hù)的一個(gè)發(fā)行版,十分建議安裝這個(gè)版本。
Conda, 一個(gè)類似 Python(x, y) 的輕量級(jí)發(fā)行版。他支持的庫(kù)稍微少一點(diǎn)但是常用的也基本包括了,它提供了一個(gè)額外的包裹管理命令還支持 Python 3.x,同時(shí)提供簡(jiǎn)潔版的 Miniconda 供自己手動(dòng)選擇庫(kù)進(jìn)行下載。
開(kāi)發(fā)相關(guān)工具
首先,你需要一份文檔
對(duì)于 Python 這樣的語(yǔ)言,你覺(jué)得你學(xué)到什么時(shí)候算是完全掌握呢?你也許會(huì)想也許哪一天你記得大部分函數(shù)的名字很怎么用,不用打幾行就 Google 搜一下的時(shí)候,就算學(xué)會(huì)了。這樣的理解對(duì)了一半,等你熟悉 Python 以后你的卻不應(yīng)該常搜索;但前一半?yún)s不一定,我個(gè)人認(rèn)為你并不需要記住龐大的標(biāo)準(zhǔn)庫(kù)中的內(nèi)容,很多時(shí)候你只要清楚要在哪里能找到相應(yīng)的文檔就行了。
Python 在這方面可以說(shuō)是做的非常非常非常好。在真正著手開(kāi)發(fā)之前,你應(yīng)該在下載一份離線的文檔。在這個(gè)頁(yè)面(如果打不開(kāi)的話試試這里,你懂的)下載一份 HTML 格式的,比如是 2.7.3 版那么對(duì)應(yīng)的文檔名字應(yīng)該是 python-2.7.3-docs-html.zip。下好后把它在一個(gè)你喜歡的地方解壓出來(lái),打開(kāi)其中的 index.html,這就是這個(gè)文檔的主頁(yè)。你可以看到他分為很多部分,包括語(yǔ)言的參考,標(biāo)準(zhǔn)庫(kù)和其他很多方便的文檔。

如果你一下不知道從哪里看起,這份文檔還有一個(gè)非常棒的功能??吹阶筮叺?Quick Search 欄,我在上圖中也有標(biāo)注起來(lái)。當(dāng)你需要對(duì)某個(gè)函數(shù)或者標(biāo)準(zhǔn)庫(kù)進(jìn)行進(jìn)一步了解的時(shí)候,你可以在這邊來(lái)進(jìn)行搜索。這里的搜索是火星科技驅(qū)動(dòng)的離線狀態(tài)下也能夠使用的!比如輸入 urllib.urlencode,你可以很方便的找到它對(duì)應(yīng)的頁(yè)面?;居辛诉@份文檔,你可以避免掉很多瘋狂搜索的情況。同樣的,當(dāng)你使用某個(gè)第三方庫(kù)的時(shí)候,你最好也在他的站點(diǎn)上找找有沒(méi)有一份離線文檔,因?yàn)?Python 項(xiàng)目很多都有著很贊的文檔。
開(kāi)發(fā)環(huán)境的選擇
如果你選擇用 IDE 的話,現(xiàn)在的選擇就非常多了,包括 PyCharm, Python Tools for Visual Studio。你也可以硬派一點(diǎn)用一個(gè)文本編輯器直接寫。但我強(qiáng)烈建議不要使用 Python 發(fā)行版自帶的那個(gè) IDLE。開(kāi)發(fā)者沒(méi)有真的認(rèn)為誰(shuí)會(huì)仔細(xì)用那它,一直以來(lái)沒(méi)有什么新功能,運(yùn)行效率不行,而且會(huì)出詭異的問(wèn)題(比如會(huì)報(bào)什么 socket 錯(cuò)誤 )。希望你花些時(shí)間找個(gè)順手的工具,只要不是 IDLE 就可以。
選擇 PyDev 作為 IDE
Python 集成開(kāi)發(fā)環(huán)境的選擇好像一直以來(lái)也是一個(gè)很難抉擇的問(wèn)題。在嘗試過(guò)很多個(gè)工具后我發(fā)現(xiàn)基于 Eclipse 的 PyDev 絕對(duì)是功能最為完整的一個(gè) IDE 。除了斷點(diǎn)調(diào)試之外,PyDev 的代碼自動(dòng)補(bǔ)全可能是現(xiàn)在這類 IDE 中最強(qiáng)力的。
如果你安裝了 Python(x, y) 的話,PyDev 就已經(jīng)在你的機(jī)器上了。如果沒(méi)有的話請(qǐng)按照這篇文章來(lái)進(jìn)行安裝。
設(shè)置上有一些需要注意的地方。首先在打開(kāi) PyDev ,打開(kāi)菜單中 Window -> Preferences,在彈出對(duì)話框中左邊找到 PyDev -> Editor -> Code Completion。這里可以設(shè)置代碼自動(dòng)補(bǔ)全的相關(guān)信息??梢越档?Autocompletion delay 來(lái)更早的提示代碼,并且將 Request completion on 系列盡可能勾上,讓 PyDev盡可多的提示代碼。
之后再找到 Interpreter Python 選項(xiàng)卡,這里可以設(shè)置所謂 Forced Buildins,可以強(qiáng)制引入某些第三方庫(kù)從而完成代碼補(bǔ)全。就我的經(jīng)驗(yàn)來(lái)看大部分第三方庫(kù)在這樣設(shè)置后都能進(jìn)行基本的補(bǔ)全。具體的做如圖中,選擇到對(duì)應(yīng)的選項(xiàng)卡,點(diǎn)擊 New,并輸入你需要的模塊名字即可。

設(shè)置后總體效果絕對(duì)是同類IDE中比較好的:

IPython 替代 Python Shell
在學(xué)習(xí) Python 的時(shí)候應(yīng)該都接觸過(guò) Python 的 Shell,能夠輸入 Python 語(yǔ)句并且立即返回結(jié)果。而 IPython就是一個(gè)豪華加強(qiáng)版的 Python Shell。如果你安裝了 Python(x, y) 的話,那 IPython 已經(jīng)在你的機(jī)器上了。如果沒(méi)有的話那么請(qǐng)在這里下載 Windows Installer 進(jìn)行安裝。在安裝這個(gè)之后還需要安裝 pyreadline 讓 IPython 開(kāi)啟高亮和自動(dòng)補(bǔ)全功能。
之后你在命令行下需要 python 的時(shí)候改為輸入 ipython 就能使用它了。開(kāi)啟 IPython 看看,首先感覺(jué)的不同應(yīng)該是這個(gè)是有顏色的。我們來(lái)看看它提供的一些基礎(chǔ)而實(shí)用的功能吧。首先是自動(dòng)補(bǔ)全,一種是簡(jiǎn)單的關(guān)鍵字補(bǔ)全,另外一種是對(duì)象的方法和屬性補(bǔ)全。作為例子,我們先引入 sys 模塊,之后再輸入 sys. (注意有個(gè)點(diǎn)),此時(shí)按下 tab 鍵,IPython 會(huì)列出所有 sys 模塊下的方法和屬性。因?yàn)槭窃诨?dòng)模式下進(jìn)行的,此時(shí)的 Python 語(yǔ)句實(shí)實(shí)在在的被執(zhí)行了,所以對(duì)普通 object 的補(bǔ)全也是很完好的。

接著上面的例子,我們輸入 sys?,這樣會(huì)顯示出 sys 模塊的 docstring及相關(guān)信息。很多時(shí)候這個(gè)也是很方便的功能。
IPython 實(shí)用技巧
這里再介紹下 IPython 使用中的一些實(shí)用功能。在學(xué)習(xí) Python 時(shí)你可能看到在循環(huán)或者函數(shù)返回時(shí)可以賦值給 _ 來(lái)表示忽略某個(gè)返回值。其實(shí)這只是一個(gè)常用的習(xí)慣。事實(shí)上 _ 是一個(gè)合法的變量名,而且在 Python shell 下 _ 總是被賦予之前最后一個(gè)輸出的值。這里看個(gè)例子應(yīng)該就能清楚:
>>> import string
>>> string.letters
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
>>> print _
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
舉個(gè)實(shí)際的例子,比如你在調(diào)試時(shí)讀文件的時(shí)候直接進(jìn)行 f.read() ,你看了看發(fā)現(xiàn)輸出結(jié)果很有意思,想要對(duì)它進(jìn)行進(jìn)一步處理,但發(fā)現(xiàn)讀的時(shí)候忘記賦值了。以往你只能嘆嘆氣重新開(kāi)文件再讀一次,現(xiàn)在你只要執(zhí)行 result = _,把 _ 附到另外一個(gè)變量就可以了。
IPython 還有強(qiáng)大之處很大部分還體現(xiàn)在它的 magic function 中。它是指的在 IPython 環(huán)境下執(zhí)行以 % 開(kāi)頭的一些命令來(lái)對(duì) IPython 進(jìn)行一些設(shè)定或者執(zhí)行某些功能。在 IPython 中輸入 %lsmagic 就能列出所有的 magic functions。在這里簡(jiǎn)單介紹下幾個(gè)比較有意思的,你也可以自己通過(guò)查看文檔來(lái)找找有哪些你特別用的到得。
之前看到能用
?來(lái)查詢函數(shù)的文檔,對(duì)于 magic function 也是如此。比如%run?。!cd ..在命令前面加上!則它會(huì)被作為命令行命令執(zhí)行,這樣你就不用退出 IPython 來(lái)進(jìn)行命令行操作。%run foo.py在當(dāng)前環(huán)境下直接執(zhí)行foo.py,效果跟命令行下調(diào)用ipython foo.py相同。%time foo.bar()跟timeit decorator作用相同,進(jìn)行簡(jiǎn)單的 profile。%hist能顯示之前輸入過(guò)的命令的歷史,同時(shí)你可以用In[<linenumber>]來(lái)訪問(wèn)之前的命令。比如%exec In[10]就能執(zhí)行列表中第十行。%rep類似上面的_變量,但是是以字串的形式返回最后,如果
%automagic是打開(kāi)的狀態(tài)的話,所有 magic function 不需要在前面加%就能正確調(diào)用。
在當(dāng)前 IPython 版本中還有一個(gè)由于安全原因沒(méi)有默認(rèn)引入的 %autoreload,它的作用是在可以自動(dòng)重新載入你調(diào)用的函數(shù),以及其相關(guān)模塊。接觸過(guò) django 的同學(xué)對(duì)這個(gè)應(yīng)該比較熟悉,在 IPython 中的效果就是,當(dāng)你在調(diào)試一個(gè)一直在反復(fù)改動(dòng)的函數(shù)時(shí),你可以開(kāi)啟這個(gè)功能保證每次調(diào)用都會(huì)重新讀取最新的版本,讓你在源碼中的改動(dòng)馬上生效。在 IPython 中執(zhí)行
import ipy_autoreload
%%autoreload 2
這樣 IPython 會(huì)對(duì)所有的模塊都進(jìn)行 autoreload。你可以通過(guò)執(zhí)行 %autoreload? 來(lái)查詢它的文檔來(lái)進(jìn)行進(jìn)一步設(shè)定。如果你希望 IPython 每次啟動(dòng)自動(dòng)載入次功能,那么可以通過(guò)配置 ipythonrc (在 Windows 下可以在 C:\Users\<username>\_ipython\ipythonrc.ini 找到) 來(lái)進(jìn)行相關(guān)設(shè)置。
最后還有一個(gè)很神奇的功能。如果你的程序是由命令行開(kāi)始執(zhí)行的,即在命令行下輸入 python foo.py(大部分 Python 程序都是),那么你還可以利用 IPython 在你的程序任意地方進(jìn)行斷點(diǎn)調(diào)試!在你程序中任意地方,加入如下語(yǔ)句:
from IPython.Shell import IPShellEmbed
IPShellEmbed([])()
注意:最近 IPython 發(fā)布了 0.11 版本,各方面變化都非常大,API 也經(jīng)過(guò)了重新設(shè)計(jì)。如果你使用的是 0.11 那么上面兩行對(duì)應(yīng)的是這樣的:
from IPython import embed
embed()
再和平常一樣運(yùn)行你的程序,你會(huì)發(fā)現(xiàn)在程序運(yùn)行到插入語(yǔ)句的地方時(shí),會(huì)轉(zhuǎn)到 IPython 環(huán)境下。你可以試試運(yùn)行些指令,就會(huì)發(fā)現(xiàn)此刻 IPython 的環(huán)境就是在程序的那個(gè)位置。你可以逐個(gè)瀏覽當(dāng)前狀態(tài)下的各個(gè)變量,調(diào)用各種函數(shù),輸出你感興趣的值來(lái)幫助調(diào)試。之后你可以照常退出 IPython,然后程序會(huì)繼續(xù)運(yùn)行下去,自然地你在當(dāng)時(shí) IPython 下執(zhí)行的語(yǔ)句也會(huì)對(duì)程序接下來(lái)的運(yùn)行造成影響。
這個(gè)方法我實(shí)在這里看到的。想象一下,這樣做就像讓高速運(yùn)轉(zhuǎn)的程序暫停下來(lái),你再對(duì)運(yùn)行中的程序進(jìn)行檢查和修改,之后再讓他繼續(xù)運(yùn)行下去。這里舉一個(gè)例子,比如編寫網(wǎng)頁(yè) bot ,你在每取回一個(gè)頁(yè)面后你都得看看它的內(nèi)容,再嘗試如何處理他獲得下一個(gè)頁(yè)面的地址。運(yùn)用這個(gè)技巧,你可以在取回頁(yè)面后讓程序中斷,再那里實(shí)驗(yàn)各種處理方法,在找到正確的處理方式后寫回到你的代碼中,再進(jìn)行下一步。這種工作流程只有像 Python 這種動(dòng)態(tài)語(yǔ)言才可以做到。
pip 管理第三方庫(kù)
Python 的一大優(yōu)勢(shì)就是有極為大量的第三方庫(kù),包括各個(gè)方面的引用。然而安裝第三方庫(kù)對(duì)沒(méi)有掌握方法的同學(xué)來(lái)說(shuō)會(huì)變得很讓人煩惱。事實(shí)上 Python 第三方庫(kù)的安裝和管理有著一個(gè)一個(gè)唯一正確的做法,這個(gè)做法要求你什么其他的都不用干,只要輸入你要安裝庫(kù)的名字就可以了。
setuptools 也包在 Python(x, y) 當(dāng)中。如果沒(méi)有的話,要首先先安裝 setuptools ,這個(gè)其實(shí)就是一個(gè)安裝第三方庫(kù)的軟件。選擇對(duì)應(yīng)版本的 Windows Installer 進(jìn)行下載和安裝后,打開(kāi)一個(gè)命令行窗口,輸入:
easy_install pip
如果提示找不到程序,那么說(shuō)明你當(dāng)前沒(méi)有設(shè)定好環(huán)境變量。安裝官方提供的 Python 安裝包的話肯定會(huì)有這個(gè)問(wèn)題,而且很可能暫時(shí)不會(huì)修正,這就是牛逼程序員的倔強(qiáng)。具體做法是 右鍵我的電腦 - 屬性 - 高級(jí)系統(tǒng)設(shè)置 - 環(huán)境變量 - 將 C:\python2*\Scripts 加入到 PATH 那一組當(dāng)中。這樣做的效果就是在任何地方的命令行下輸入命令,那么系統(tǒng)會(huì)額外查找我們?cè)O(shè)定的那個(gè)目錄中的內(nèi)容。之后再執(zhí)行上面的命令,裝好了以后我們就要棄用 setuptools,轉(zhuǎn)投 pip。要安裝任何一個(gè)庫(kù),你只要找到他的名字(不需要版本號(hào)),用 pip 安裝即可。譬如安裝 django,那么輸入如下命令即可:
pip install django
其實(shí)之前 easy_install 跟 pip 效用是類似的,都是在官方的第三方庫(kù)索引 PyPI 查詢信息并進(jìn)行下載和安裝。pip 的優(yōu)勢(shì)在于支持更高級(jí)的功能,譬如虛擬環(huán)境,安裝失敗不會(huì)殘留破損的庫(kù),更重要的是 pip 還可以進(jìn)行卸載。輸入下面命令就能卸載一個(gè)之前由 pip 進(jìn)行安裝的庫(kù)。繼續(xù)上面的例子,現(xiàn)在要卸載 django:
pip uninstall django
這是 setuptools 所缺失的功能。需要額外說(shuō)明的是大部分純 Python 的庫(kù)都能用這個(gè)方法在 Windows 下裝上,但是需要編譯 C 語(yǔ)言模塊的一般都不太可能成功。遇到這種情況,在相應(yīng)的庫(kù)德站點(diǎn)上找找有沒(méi)有對(duì)應(yīng)的 Windows 安裝包。
用 virtualenv 構(gòu)建虛擬 Python 環(huán)境
如果你使用過(guò) Python 做過(guò) Web 開(kāi)發(fā),或者你有需求在本機(jī)上安裝多個(gè)版本的 Python 來(lái)測(cè)試你的代碼能否跑再 2.5, 2.6, 2.7 各個(gè)版本上,或者你的不同項(xiàng)目依賴于一個(gè)第三方庫(kù)的不同版本;再或者,有時(shí)候你就是想要一個(gè)沒(méi)有之前安裝過(guò)的亂七八糟的庫(kù),一個(gè)干凈的 Python 環(huán)境。這種時(shí)候 virtualenv 就能幫上你的忙。它能利用安裝好的 Python ,在同一臺(tái)機(jī)器上建立一個(gè)或多個(gè)互不相干的虛擬 Python 環(huán)境,且能隨時(shí)切換。如果你看到這里還不覺(jué)得這個(gè)有什么用處,那不妨看下去留下點(diǎn)印象,等哪天你有這類需求的時(shí)候能找到這個(gè)簡(jiǎn)單實(shí)用的工具。
和其他第三方庫(kù)一樣,我們可以通過(guò) pip 輕松安裝:
pip install virtualenv
安裝完成后你可以開(kāi)啟一個(gè)命令行窗口,輸入 virtualenv 看看能不能找到這個(gè)腳本。如果有問(wèn)題的話,請(qǐng)按照上面介紹過(guò)的步驟檢查下是否設(shè)置好了 PATH。之后我們可以在一個(gè)方便的地方建立一個(gè)虛擬環(huán)境。建立 C:\envs\ 文件夾,命令行下 cd 到該文件夾中,輸入:
virtualenv --no-site-packages --python=C:\Python26\python.exe envtest
之后應(yīng)該會(huì)看到一個(gè)叫 envtest 的文件夾。這就是一個(gè)新建立的虛擬環(huán)境(virtual enviroment)。我們不妨先激活它來(lái)看看應(yīng)該怎么用。命令行下執(zhí)行 envtest\Scripts\activate.bat,這時(shí)是你會(huì)發(fā)現(xiàn)命令行變成這個(gè)樣子:
(envtest) c:\>
提示符前面的 (envtest) 就是該環(huán)境已被激活的標(biāo)志。這樣你就可以在這個(gè)虛擬環(huán)境下進(jìn)行工作了。執(zhí)行 pip freeze ,你會(huì)發(fā)現(xiàn)... 你會(huì)發(fā)現(xiàn)什么都沒(méi)有啊。執(zhí)行 pip help,你可以看到 pip freeze 是輸出當(dāng)前 Python 環(huán)境下已經(jīng)安裝的所有第三方庫(kù)。因?yàn)槲覀儎?chuàng)建此環(huán)境時(shí)開(kāi)啟了選項(xiàng) --no-site-packages,意思就是在創(chuàng)建此虛擬環(huán)境中不從系統(tǒng) Python 中把已經(jīng)安裝了的庫(kù)也安裝到這里來(lái),所以這里是一個(gè)干凈的新 Python 環(huán)境。你可以在這里調(diào)用 pip 或者 easy_install 來(lái)安裝各種你需要的庫(kù)到這個(gè)環(huán)境中來(lái),而不會(huì)影響到你系統(tǒng)中 Python 的情況,所以說(shuō)它是一個(gè)虛擬的 Python 環(huán)境。
我們?cè)倩仡^看下 envtest 目錄的結(jié)構(gòu),其下面的 Scripts 目錄中有 python.exe pip.exe 這些程序,在虛擬環(huán)境已激活的情況下,你調(diào)用 python 或者 pip 都是調(diào)用的此目錄中的程序。此時(shí)系統(tǒng)中的 python.exe 被 virtualenv 通過(guò)設(shè)置環(huán)境變量隱藏了起來(lái)。而 Lib 目錄下就是存放各種新安裝的庫(kù)。
到這里你應(yīng)該已經(jīng)對(duì) virtualenv 基本操作已經(jīng)了解了,下面講些使用上的注意事項(xiàng):
調(diào)用
activate.bat開(kāi)啟虛擬環(huán)境,你也可以用同目錄下的deactivate.bat來(lái)退出該虛擬環(huán)境。建立虛擬環(huán)境時(shí)的參數(shù)
--python=C:\Python26\python.exe是用來(lái)指定你想使用 Python 程序位置,所以你可以建立多個(gè)虛擬環(huán)境來(lái)指向多個(gè) Python 版本。另外你要注意的是如果你在系統(tǒng)上安裝了多個(gè)版本的 Python, 你最先安裝的一個(gè)版本會(huì)被當(dāng)做主要版本,你在命令行下打python時(shí),調(diào)用的就是最先安裝的一個(gè)版本。其實(shí)這個(gè)是按照 PATH 中設(shè)定的路徑位置來(lái)確定的,你最好把你需要主要使用的版本相關(guān)路徑放在 PATH 環(huán)境變量中最前面。比如我的機(jī)器上,就是把C:\Python26和C:\Python26\Scripts作為 PATH 最前面兩個(gè)。這樣應(yīng)該就能讓保證你主要版本的正常使用。當(dāng)你在一個(gè)虛擬環(huán)境下工作時(shí),假如你想在當(dāng)前環(huán)境下來(lái)執(zhí)行一個(gè) Python 程序,這時(shí)你在命令行下必須執(zhí)行
python foo.py,這樣 foo.py 才會(huì)在你當(dāng)前已經(jīng)激活的 virtualenv 下執(zhí)行。作為比較如果你直接執(zhí)行foo.py那么它仍然時(shí)在系統(tǒng)環(huán)境下執(zhí)行的。
另外,Linux 下可以使用 virtualenvwrapper 來(lái)進(jìn)行方便的管理和切換各個(gè)環(huán)境,可惜的是這東西在 Windows 下用不了。但幸好有一個(gè)簡(jiǎn)單的腳本 envdotpy 來(lái)幫助你使用。把 env.py 放到 PATH 上的目錄內(nèi),譬如 C:\Python26\Scripts 下。之后先打開(kāi)里面的 DEFAULT_DIR_PATH 變量,把它改成你集中存放 virtualenv 的地方,在我們上面的例子中就可以把這行改為:
DEFAULT_DIR_PATH = "C:\\envs\\"
之后你就不需要專門 cd 到這個(gè)目錄,而可以在任意路徑上通過(guò) env.py 來(lái)進(jìn)行激活,切換,退出 virtualenv 了。例如執(zhí)行: env.py envtest 就能激活 envtest 。執(zhí)行 env.py -q 就能退出任意一個(gè) virtualenv。
Winpdb 進(jìn)行可視化調(diào)試
如果你使用的 PyDev 的話那么用其自帶的斷點(diǎn)調(diào)試應(yīng)該就可以了。Winpdb則是為用其他簡(jiǎn)單編輯器進(jìn)行 Python 開(kāi)發(fā)的用戶提供一個(gè)熟悉的調(diào)試環(huán)境。Winpdb不出意料的也在 Python(x, y)當(dāng)中。所以如果裝上 Python(x, y) 你可以不斷發(fā)掘里面附帶的優(yōu)秀工具。使用方法很簡(jiǎn)單,假設(shè)程序名為 foo.py,那么在命令行中輸入:
winpdb foo.py
之后會(huì)彈出窗口,也就是一個(gè)大家都熟悉的 debug 圖形界面。需要注意的是這里需要點(diǎn)擊想要設(shè)置斷點(diǎn)的行,點(diǎn)擊 F9 設(shè)置斷點(diǎn),然后該行底色會(huì)變?yōu)榧t色,如下圖所示。

編碼問(wèn)題
作為中文用戶,初學(xué) Python 最容易碰到的問(wèn)題估計(jì)就是編碼問(wèn)題了。明明英文的都可以用到中文的時(shí)候就要出問(wèn)題,而且出錯(cuò)信息難以理解,想要解決問(wèn)題又不知道從何開(kāi)始。幸運(yùn)的是編碼問(wèn)題通過(guò)預(yù)防性的措施是很好避免的。下面從幾個(gè)方面來(lái)講講 Python 中處理中文及 Unicode 容易碰到的問(wèn)題。
Unicode 編碼基礎(chǔ)
這里非常簡(jiǎn)單的講一下編碼知識(shí),此部分表述可能不太準(zhǔn)確,如果你對(duì) Unicode 更為了解的話請(qǐng)聯(lián)系我?guī)兔m正。
你可以想象 Unicode 是一個(gè)很大的表,里面有著世界上所有的文字的個(gè)體,如英文中的字母,中文的漢字。事實(shí)上 Unicode 標(biāo)準(zhǔn)中每一個(gè)字都有一個(gè)唯一對(duì)應(yīng)的編號(hào),好比說(shuō) '中'字 對(duì)應(yīng)十六進(jìn)制 0x4E2D,而字母 'a' 對(duì)應(yīng)的是十六進(jìn)制 0x0061。這個(gè)編號(hào)是由 Unicode Consortium 這個(gè)組織來(lái)確定的。 如果說(shuō)用這個(gè)編碼來(lái)對(duì)應(yīng)字符來(lái)用于表示字符,理論上是可以的,這樣的話就是每一個(gè)數(shù)字編號(hào)能對(duì)應(yīng)一個(gè)字符。
而實(shí)際情況中,不是每篇文章都用得到世界上所有的字符。譬如一篇英文文章就只有英文字母加上一些符號(hào),用 Unicode 來(lái)進(jìn)行存儲(chǔ)的話每個(gè)字符要浪費(fèi)太多的空間。所以就有各種類型的編碼產(chǎn)生。編碼我們這里可以理解就是將一部分的 Unicode (比如說(shuō)所有的中文,或者所有的日文)字符,以某種方式確定另外一個(gè)符號(hào)來(lái)代表他。中文常用編碼有 UTF8 和 GBK,仍然以 '中'字 為例, UTF8 編碼將對(duì)應(yīng) '中'字 的 Unicode 編號(hào) 0x4E2D 拆成三個(gè)的編號(hào)的組合,[0xE4, 0xB8, 0xAD],只有這幾個(gè)連在一起的時(shí)候才會(huì)被作為一個(gè) '中'字 顯示出來(lái);作為對(duì)比,GBK 編碼將 '中'字 對(duì)應(yīng)的 Unicode 編號(hào) 0x4E2D 編碼成為兩個(gè)編號(hào)的組合 [0xD6, 0xD0],在 GBK 編碼環(huán)境下只有這兩個(gè)編號(hào)一起時(shí),才會(huì)顯示為 '中'字。
上面的例子中,如果把 UTF8 編碼后的 [0xE4, 0xB8, 0xAD] 放到 GBK 環(huán)境下來(lái)顯示會(huì)怎樣?這幾個(gè)編號(hào)跟 '中'字 在 GBK 下的編碼 [0xD6, 0xD0],不同,則顯然不會(huì)顯示為 '中'字。這三個(gè)字符會(huì)跟排在其前后的字符一起,按照 GBK 的編碼規(guī)則找有沒(méi)有對(duì)應(yīng)的字符。結(jié)果有可能顯示出一個(gè)毫不相關(guān)的字符,有時(shí)候?yàn)榉?hào)或者干脆不顯示,這種情況就算產(chǎn)生了亂碼。
Python 2.x 中的 String 與 Unicode
在 Python 2.x 中是有兩種字串符相關(guān)類型的,分別為 String 和 Unicode,兩者提供的接口非常類似,有時(shí)候又能自動(dòng)轉(zhuǎn)換,蠻容易誤導(dǎo)人的。在 Python 3 中 這兩個(gè)類型分別用 Bytes 和 String 替代了。這個(gè)名字更能說(shuō)明兩者的本質(zhì):Python 2.x 中的 String 中存儲(chǔ)的是沒(méi)有編碼信息的字節(jié)序列,也就是說(shuō) String 中存儲(chǔ)的是已經(jīng)編碼過(guò)后的序列,但他并不知道自身是用的哪種編碼。相反的 Unicode 中存儲(chǔ)的是記載了編碼的字串信息,其中存儲(chǔ)的就是相應(yīng)字符的 Unicode 編號(hào)。在這里用程序來(lái)說(shuō)明,我們建立一個(gè)簡(jiǎn)單的腳本名字為 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)
前面兩行后面會(huì)解釋到,就是限定運(yùn)行環(huán)境以及該腳本文件的編碼格式。此腳本在這里可以下載,如果你要自己寫的話請(qǐng)務(wù)必確保腳本的編碼是 utf8 而不是別的。在 Windows 下的運(yùn)行結(jié)果在這里,我覺(jué)得正好能說(shuō)明問(wèn)題:
C:\SHARED\Dev\scripts>encoding.py
榪
這也
12
5
這里需要說(shuō)明,我們的程序是 UTF8 編碼,主要意義是該程序中的所有直接寫出來(lái)的字串符(用"", ''括起來(lái)的字串符)是運(yùn)用 UTF8 格式編碼的;然而 Windows 下的命令行是 GBK 環(huán)境。這里 strs 是一個(gè) String。事實(shí)上在 Python 2.x 中直接寫在程序中的字串符,其類型都是 String(這里不考慮 string literal)。我們先直接輸出 strs[0:2],得到的是一個(gè)亂碼字符(這個(gè)字符只是碰巧湊成是一個(gè)字)。如上面說(shuō)的,String 中存儲(chǔ)的是沒(méi)有編碼信息的字串序列,這里就是將strs中前兩個(gè)編號(hào)取出并嘗試顯示。由于命令行環(huán)境為 GBK 編碼,這里對(duì)應(yīng)的字碰巧湊成了一個(gè)字,但是跟原本的字沒(méi)有任何關(guān)系。
unis 是由一個(gè) String 調(diào)用 decode() 方法得到,這正是在 Python 2.x 中取得 Unicode 的最基本的方式。由于 String 并不知道它本身是由什么編碼格式來(lái)進(jìn)行的編碼,這里是我們的責(zé)任來(lái)確定他原來(lái)是用哪種編碼方式進(jìn)行編碼。我們知道代碼中的編碼格式是 UTF8,所以我們可以用調(diào)用 String 的 decode() 方法來(lái)進(jìn)行反編碼,也就是解碼, 把字串符從某種編碼后的格式轉(zhuǎn)換為其唯一對(duì)應(yīng)的 Unicode 編號(hào)。unis 為解碼獲得的結(jié)果,其在 Python 2.x 中對(duì)應(yīng)類型就是 Unicode,其中存儲(chǔ)的就是 每個(gè)字符對(duì)應(yīng)的 Unicode 編號(hào)。
我們嘗試輸出 unis 的前兩個(gè)字符,在這里我們調(diào)用了 Unicode 的 encode() 方法。這就是編碼的過(guò)程。我們知道 Windows 命令行下的編碼是 GBK,只有采用 GBK 編碼的字符才能正確顯示。所以在這里我們通過(guò)調(diào)用 Unicode 的 encode() 方法,將 unis 中存儲(chǔ)的 Unicode 編號(hào) 按照 GBK 的規(guī)則來(lái)進(jìn)行編碼,并輸出到屏幕上。這里我們看到這里正確的顯示了 unis 中的前兩個(gè)字符。要注意的是在命令行中直接 print Unicode 的話 Python 會(huì)自動(dòng)根據(jù)當(dāng)前環(huán)境進(jìn)行編碼后再顯示,但這樣掩蓋了兩者的區(qū)別。建議總是手動(dòng)調(diào)用 encode 和 decode 方法,這樣自己也會(huì)清楚一些。
后面兩者長(zhǎng)度的差別也是佐證我們之前的例子。strs 中存儲(chǔ)的是 UTF8 編碼后的編號(hào)序列,上面看到一個(gè)中文字符在 UTF8 編碼后變成三個(gè)連續(xù)的,所以 strs 長(zhǎng)度為 3x4 = 12。你可以想象 strs 中存放的并不是中文,而是一系列沒(méi)有意義的比特序列;而 unis 中存儲(chǔ)的是對(duì)應(yīng)的中文的 Unicode 編碼。我們知道每一個(gè)字符對(duì)應(yīng)一個(gè)編號(hào),所以五個(gè)字對(duì)應(yīng)五個(gè)編號(hào),長(zhǎng)度為 5。
避免,和解決編碼產(chǎn)生的問(wèn)題
了解了 Python Unicode 編碼解碼的這些概念后,我們來(lái)看看如何盡量的避免遇到讓人煩心的編碼問(wèn)題。
首先如果你的代碼中有中文,那么一定要?jiǎng)?wù)必聲明代碼的編碼格式。根據(jù) PEP-0263 中的介紹,在程序的最開(kāi)始加上以下兩行注釋就能確定編碼:
#!/usr/bin/python
# -*- coding: utf-8 -*-
其中 utf-8 就是指定的編碼格式。事實(shí)上你應(yīng)該總是使用 UTF8 作為你 Python 程序的編碼格式,因?yàn)槲磥?lái)的 Python 3 所有文件都將默認(rèn)以 UTF8 編碼。另外除了聲明,你必須確定你用來(lái)編輯 Python 程序的編輯器是不是真的以 UTF8 編碼來(lái)存儲(chǔ)文件。
之后就是養(yǎng)成關(guān)于編碼解碼的好習(xí)慣。當(dāng)你的程序有 String 作為輸入時(shí),應(yīng)該盡早的將其轉(zhuǎn)換為 Unicode,再在程序中進(jìn)行處理。再輸出的時(shí)候,也要盡可能玩,直到最后輸出的時(shí)刻才將 Unicode 編碼為所需編碼格式的 String 進(jìn)行輸出。同樣的你必須保持你程序內(nèi)部所有參與運(yùn)算的字串都是 Unicode 格式。很多著名的 Python 庫(kù)例如 django 就是采用的這種方式,效果也蠻好。千萬(wàn)不要依賴 Python 自己進(jìn)行兩者之間的轉(zhuǎn)換,也不要將 String 和 Unicode 放在一起運(yùn)算,這些行為一方面十分容易引起錯(cuò)誤,另一方面在 Python 3 中已經(jīng)無(wú)法再現(xiàn)。
雖說(shuō)確定 String 的編碼格式是程序員的責(zé)任,但有時(shí)候你真的不知道有些字串符到底是什么編碼的。這里有一個(gè)神奇 chardet 能夠幫助你。以下是摘自其頁(yè)面上的例子,很好了說(shuō)明了它的作用:讀入任意一串字符,猜測(cè)其編碼格式,并且給出猜測(cè)的確信度。
>>> 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 直接報(bào)錯(cuò),多半是字串經(jīng)過(guò)多次錯(cuò)誤編碼解碼,要從別的地方找辦法解決問(wèn)題。
在處理包含漢字的文本文件時(shí),一個(gè)很常見(jiàn)的問(wèn)題就是有時(shí)候會(huì)碰到帶有 UTF BOM 的文件。這個(gè)簡(jiǎn)單講就是文件頭幾個(gè)字節(jié)是用來(lái)表示文件是大端還是小端表示。在實(shí)際中用的很少,而且會(huì)帶來(lái)很頭疼的問(wèn)題。有時(shí)候你確定你有一個(gè)文件是 UTF8 編碼的,但讀進(jìn)來(lái)頭幾個(gè)字節(jié)就出錯(cuò),那么十有八九就是這個(gè)的問(wèn)題。Python 在讀取文件時(shí)仍然是所有字節(jié)順序讀進(jìn)來(lái),不會(huì)透明的處理這個(gè)東西。所以要么你可以用編輯器來(lái)把文件另存為無(wú) BOM 的,要么在 Python 中做處理。在標(biāo)準(zhǔn)庫(kù)中有 codec 里面提供了相關(guān)功能:
import codecs
s = f.read(3)
if s == codecs.BOM_UTF8:
print "BOM detected"
這樣可以簡(jiǎn)單檢測(cè) BOM 是否存在,剩下的部分就要你自己發(fā)揮了。
如果上面的介紹還不能讓你理解 Unicode 的概念,這里還有幾篇關(guān)于這個(gè)問(wèn)題的文章:
Unicode In Python, Completely Demystified 特別針對(duì) Python 下的 Unicode 處理進(jìn)行詳細(xì)的講解。
其他
除了上面幾個(gè)重要的問(wèn)題之外,剩下的資源。
Vim Python開(kāi)發(fā) 相關(guān)資源
事實(shí)上我現(xiàn)在自己是在用 Vim 寫 Python,感覺(jué)也蠻不錯(cuò)。以下是相關(guān)資源。
UltimateVimPythonSetup
比較新的一個(gè)專門針對(duì) Python 的 Vim 配置文件。Vim as Python IDE
只要搜 Python 和 Vim 就一定會(huì)找到這一篇文章。vimcolorschemetest
所有的Vim 配色方案都在集結(jié)在這里。Python 相關(guān) Vim 插件
pythoncomplete.vim
按上面的介紹配置一下,在自動(dòng)輸入的時(shí)候按Ctrl-X, Ctrl-O就有很強(qiáng)力的自動(dòng)補(bǔ)全了。
python.vim
加強(qiáng)語(yǔ)法的高亮。
pyflakes.vim
很棒的語(yǔ)法檢查,分析你的語(yǔ)法看避免低級(jí)錯(cuò)誤。注意這個(gè)在Vim7.2下才有用,
如果是7.1則一點(diǎn)效果都沒(méi)有...
其他相關(guān)資源
用Python做科學(xué)計(jì)算
這個(gè)把Python(x,y)里面所有的模塊基本上都講了一遍,我覺(jué)得外國(guó)人肯定都希望這個(gè)有個(gè)英文版的。PyMOTW
這個(gè)名字看起來(lái)像個(gè)Python庫(kù)(其實(shí)它還真的是一個(gè)...),但他總體來(lái)說(shuō)其實(shí)是一份文檔,
"Python每周一個(gè)模塊"。作者持續(xù)幾年每周介紹一個(gè)Python標(biāo)準(zhǔn)庫(kù)中的庫(kù)。你可以把他看做是一個(gè)Python標(biāo)準(zhǔn)庫(kù)文檔的一個(gè)很棒的補(bǔ)充,當(dāng)你看標(biāo)準(zhǔn)庫(kù)中的介紹看的云里霧里的時(shí)候,不妨來(lái)這邊找找相應(yīng)的介紹。因?yàn)檫@里的例子給的很全,而且基本上你用的到的偏門的庫(kù)這里都有介紹哦。另外一個(gè)好消息是PyMOTW有一份很棒中文翻譯版。reddit.com/r/python 和
python.org planet
Python 相關(guān)的文章和資源。就我個(gè)人經(jīng)歷來(lái)說(shuō),每次都能在這里看到很多有用的東西。