Python 二三事

(這是很早之前寫的但內(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教程有:

如果你還沒(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ù)和其他很多方便的文檔。

Python 文檔
Python 文檔

如果你一下不知道從哪里看起,這份文檔還有一個(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,并輸入你需要的模塊名字即可。

Forced Buldins設(shè)置
Forced Buldins設(shè)置

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

Eclipse 補(bǔ)全效果
Eclipse 補(bǔ)全效果

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ǔ)全也是很完好的。

IPython
IPython

接著上面的例子,我們輸入 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_installpip 效用是類似的,都是在官方的第三方庫(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:\Python26C:\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色,如下圖所示。

Winpdb
Winpdb

編碼問(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)用 Stringdecode() 方法來(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)用了 Unicodeencode() 方法。這就是編碼的過(guò)程。我們知道 Windows 命令行下的編碼是 GBK,只有采用 GBK 編碼的字符才能正確顯示。所以在這里我們通過(guò)調(diào)用 Unicodeencode() 方法,將 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)用 encodedecode 方法,這樣自己也會(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)換,也不要將 StringUnicode 放在一起運(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)題的文章:

其他

除了上面幾個(gè)重要的問(wèn)題之外,剩下的資源。

Vim Python開(kāi)發(fā) 相關(guān)資源

事實(shí)上我現(xiàn)在自己是在用 Vim 寫 Python,感覺(jué)也蠻不錯(cuò)。以下是相關(guān)資源。

  1. UltimateVimPythonSetup
    比較新的一個(gè)專門針對(duì) Python 的 Vim 配置文件。

  2. Vim as Python IDE
    只要搜 Python 和 Vim 就一定會(huì)找到這一篇文章。

  3. vimcolorschemetest
    所有的Vim 配色方案都在集結(jié)在這里。

  4. 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)資源

  1. 用Python做科學(xué)計(jì)算
    這個(gè)把Python(x,y)里面所有的模塊基本上都講了一遍,我覺(jué)得外國(guó)人肯定都希望這個(gè)有個(gè)英文版的。

  2. 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有一份很棒中文翻譯版。

  3. reddit.com/r/python
    python.org planet
    Python 相關(guān)的文章和資源。就我個(gè)人經(jīng)歷來(lái)說(shuō),每次都能在這里看到很多有用的東西。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容