IPython,讓Python顯得友好十倍的外套——windows XP/Win7安裝詳解

IPython,讓Python顯得友好十倍的外套——windows XP/Win7安裝詳解

前言

學(xué)習(xí)python,官方版本其實(shí)足夠了。但是如果追求更好的開發(fā)體驗(yàn),耐得住不厭其煩地折騰。那么我可以負(fù)責(zé)任的告訴你:IPython是我認(rèn)為的唯一顯著好于原版python的工具。

整理了《Python 二三事》:http://pre-sence.com/archives/python-intro ? 《Python 四五事》:http://pre-sence.com/archives/python-misc 并加入安裝IPython部分。

寫這篇隨筆的原因是:忽然醒悟之前我安裝IPython折騰許久不成功可能是我未能想起pip或easy_install這兩個python的上帝工具。參考:Python包管理工具pip與easy_install

個人經(jīng)驗(yàn)總結(jié):IPython,是學(xué)習(xí)python的利器,是讓Python顯得友好十倍的外套,是我唯一的強(qiáng)烈推薦。

安裝IPython

任何Linux發(fā)行版對編程者都十分友好

Ubuntu為例: sudo apt-get install ipython

windows環(huán)境:

1、下載ez_setup.py,右擊左邊鏈接,另存為,使用python ez_setup.py運(yùn)行,或直接雙擊。

2、步驟1成功后,cmd下輸入命令easy_install -h可以測試,正常反應(yīng)說明已經(jīng)可以使用easy_install了。

3、cmd下輸入easy_install pip安裝pip,這是因?yàn)閜ip正是easy_install的下一代,比easy_install好用。

4、步驟3成功后,pip install ipython。

5、如果步驟4不行,退一步,使用easy_install ipython安裝。

運(yùn)行IPython

cmd提示符下,輸入ipython運(yùn)行就可以使用除了原python外,IPython多出來的貼心的“I”了。

退出IPython

與python一樣也是輸入exit

Python實(shí)用技巧:

1、關(guān)于 "_" 字符使用

在 Python shell 下 _ 總是被賦予之前最后一個表達(dá)式的值(注:@pythonwood)。這里看個例子應(yīng)該就能清楚:

>>>importstring

>>> string.letters

'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'

>>>print_

abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ

>>>2014

2014

>>> v=_

>>> v

2014

舉個實(shí)際的例子,比如你在調(diào)試時讀文件的時候直接進(jìn)行 f.read() ,你看了看發(fā)現(xiàn)輸出結(jié)果很有意思,想要對它進(jìn)行進(jìn)一步處理,但發(fā)現(xiàn)讀的時候忘記賦值了。以往你只能嘆嘆氣重新開文件再讀一次,現(xiàn)在你只要執(zhí)行 result = _,把 _ 附到另外一個變量就可以了。

2、python -m

相信很多人應(yīng)該用過這個東西,Python 很多標(biāo)準(zhǔn)庫都提供這樣的調(diào)用方式來實(shí)現(xiàn)一些簡單的命令行功能。Python 3 現(xiàn)在自帶 pip。比如我們想使用 Python 3 的 pip 來安裝別的庫,我們可以這樣:

py -3 -m pip install bottle

跟你預(yù)料的一樣,這樣就可以了。當(dāng)然你可以用個 .bat 文件來把這些包裹起來并放在 Path 上,一個簡單的例子,把下面的內(nèi)容寫到一個叫 pip3.bat 的文件里:

@echo off

py -3 -m pip %*

并放到 Path 上,就可以方便調(diào)用了。其中 %* 負(fù)責(zé)傳遞所有的命令行參數(shù)。

實(shí)際上 python -m 可以用的東西還真的挺多,這里給出一個不完全的列表:

######################################################

# 最強(qiáng)功能

######################################################

# 局域網(wǎng)共享,宿舍中任意一臺筆記本都可以瞬間變身web資源共享服務(wù)器

# 命令ipconfig可以看到局域網(wǎng)ip地址,一般是192,172這些開頭的。

# 使用本機(jī)80端口,可任意設(shè)置。只共享當(dāng)前運(yùn)行目錄。

#

python-m SimpleHTTPServer80

#

# 本機(jī)任意瀏覽器輸入http://localhosthttp://127.0.0.1可以訪問。

# (80端口瀏覽器默認(rèn)的,不需輸入)甚至在地址欄直接輸入localhost即可。

# 局域網(wǎng),(宿舍)任意電腦輸入上面所說192或172等開頭的IP地址即可訪問。

######################################################

# 縮進(jìn)輸出 JSON

echo {"hey":"kid"} | python-m json.tool

# 簡單的執(zhí)行時間測量

python-m timeit [ix*ixforixinrange(100)]

# 簡單的 Profiling

python-m cProfile myscript.py

# 比較兩個文件夾的區(qū)別

python-m filecmp path/to/a path/to/b

# base64 轉(zhuǎn)換

echo foo bar | python-m base64

# 調(diào)用默認(rèn)瀏覽器打開一個新標(biāo)簽頁

python-m webbrowser-t http://google.com

# 生成程序文檔

python-m pydoc myscript.py

# 類似 nose 的自動搜索 unittest

python-m unittest discover

# 調(diào)用 pdb 執(zhí)行代碼

python-m pdb myscript.py

IPython實(shí)用技巧:

1、Tab自動補(bǔ)全,一種是簡單的關(guān)鍵字補(bǔ)全,另外一種是對象的方法和屬性補(bǔ)全。

作為例子,我們先引入sys模塊,之后再輸入sys.(注意有個點(diǎn)),此時按下 tab 鍵,IPython 會列出所有 sys 模塊下的方法和屬性。

接著上面的例子,我們輸入sys?,這樣會顯示出sys模塊的 docstring及相關(guān)信息。很多時候這個也是很方便的功能。

2、IPython 還有強(qiáng)大之處很大部分還體現(xiàn)在它的magic function中。它是指的在 IPython 環(huán)境下執(zhí)行以%開頭的一些命令來對 IPython 進(jìn)行一些設(shè)定或者執(zhí)行某些功能。在 IPython 中輸入%lsmagic就能列出所有的magic functions。在這里簡單介紹下幾個比較有意思的,你也可以自己通過查看文檔來找找有哪些你特別用的到得。

之前看到能用?來查詢函數(shù)的文檔,對于 magic function 也是如此。比如%run?。

!cd ..在命令前面加上!則它會被作為命令行命令執(zhí)行,這樣你就不用退出 IPython 來進(jìn)行命令行操作。

%run foo.py在當(dāng)前環(huán)境下直接執(zhí)行foo.py,效果跟命令行下調(diào)用ipython foo.py相同。

%time foo.bar()跟timeit decorator作用相同,進(jìn)行簡單的 profile。

%hist能顯示之前輸入過的命令的歷史,同時你可以用In[]來訪問之前的命令。比如%exec In[10]就能執(zhí)行列表中第十行。

%rep類似上面的_變量,但是是以字串的形式返回

最后,如果%automagic是打開的狀態(tài)的話,所有 magic function 不需要在前面加%就能正確調(diào)用。

在當(dāng)前 IPython 版本中還有一個由于安全原因沒有默認(rèn)引入的%autoreload,它的作用是在可以自動重新載入你調(diào)用的函數(shù),以及其相關(guān)模塊。接觸過django的同學(xué)對這個應(yīng)該比較熟悉,在 IPython 中的效果就是,當(dāng)你在調(diào)試一個一直在反復(fù)改動的函數(shù)時,你可以開啟這個功能保證每次調(diào)用都會重新讀取最新的版本,讓你在源碼中的改動馬上生效。在 IPython 中執(zhí)行

importipy_autoreload

%%autoreload2

這樣 IPython 會對所有的模塊都進(jìn)行 autoreload。你可以通過執(zhí)行%autoreload?來查詢它的文檔來進(jìn)行進(jìn)一步設(shè)定。如果你希望 IPython 每次啟動自動載入次功能,那么可以通過配置 ipythonrc (在 Windows 下可以在C:\Users\\_ipython\ipythonrc.ini找到) 來進(jìn)行相關(guān)設(shè)置。

3、還有一個很神奇的功能。如果你的程序是由命令行開始執(zhí)行的,即在命令行下輸入python foo.py(大部分 Python 程序都是),那么你還可以利用 IPython 在你的程序任意地方進(jìn)行斷點(diǎn)調(diào)試!

在你程序中任意地方,加入如下語句:

fromIPython.ShellimportIPShellEmbed

IPShellEmbed([])()

注意:最近 IPython 發(fā)布了0.11 版本,各方面變化都非常大,API 也經(jīng)過了重新設(shè)計。如果你使用的是 0.11 那么上面兩行對應(yīng)的是這樣的:

fromIPythonimportembed

embed()

再和平常一樣運(yùn)行你的程序,你會發(fā)現(xiàn)在程序運(yùn)行到插入語句的地方時,會轉(zhuǎn)到 IPython 環(huán)境下。你可以試試運(yùn)行些指令,就會發(fā)現(xiàn)此刻 IPython 的環(huán)境就是在程序的那個位置。你可以逐個瀏覽當(dāng)前狀態(tài)下的各個變量,調(diào)用各種函數(shù),輸出你感興趣的值來幫助調(diào)試。之后你可以照常退出 IPython,然后程序會繼續(xù)運(yùn)行下去,自然地你在當(dāng)時 IPython 下執(zhí)行的語句也會對程序接下來的運(yùn)行造成影響。

這個方法我實(shí)在這里看 到的。想象一下,這樣做就像讓高速運(yùn)轉(zhuǎn)的程序暫停下來,你再對運(yùn)行中的程序進(jìn)行檢查和修改,之后再讓他繼續(xù)運(yùn)行下去。這里舉一個例子,比如編寫網(wǎng)頁 bot ,你在每取回一個頁面后你都得看看它的內(nèi)容,再嘗試如何處理他獲得下一個頁面的地址。運(yùn)用這個技巧,你可以在取回頁面后讓程序中斷,再那里實(shí)驗(yàn)各種處理方 法,在找到正確的處理方式后寫回到你的代碼中,再進(jìn)行下一步。這種工作流程只有像 Python 這種動態(tài)語言才可以做到。

4、一個實(shí)際的例子

這里以一個簡單的例子來講解一下是怎樣的一個情況。我們要寫一個可以將簡單的數(shù)據(jù)表達(dá)式,類似1 + (2 - 3) * 456解析成樹的Pratt Parser。首先我們需要一個 lexer 把每個 token 解析出來,那么最開始的代碼就是:

# simple math expression parser

deflexer(s):

'''token generator, yields a list of tokens'''

yields

if__name__=='__main__':

fortokeninlexer("1 + (2 - 3) * 456"):

printtoken

明顯這個沒有任何意義,但現(xiàn)在程序已經(jīng)有足夠的東西能夠跑起來。我們把這個程序存為expr.py,開啟一個命令行窗口,運(yùn)行ipython然后像這樣執(zhí)行它:

$ ipython

IPython0.13.1--An enhanced Interactive Python.

?-> Introductionandoverview of IPython's features.

...

In [1]: run expr.py

1+(2-3)*456

在 IPython 里面用run跑的好處有很多,首先是你在程序執(zhí)行完畢后整個程序的狀態(tài),比如最后全局變量的值,你寫的函數(shù)這些你都是可以隨便執(zhí)行的!同樣的你可以在 IPython 里面保存一些用來測試的常量,每次用run跑的話新的程序會被重新載入,你可以這樣方便的測試每個函數(shù),有一個非常動態(tài)的環(huán)境來調(diào)試你的程序:

In [2]:printtoken# 注意這里 token 就是 __main__ 里面的那個 token 的值

1+(2-3)*456

In [3]:printlist(lexer('1+2+3'))# 可以運(yùn)行你寫的函數(shù)

['1+2+3']

然后按照之前的想法,我們嘗試把這個 lexer 寫出來。在這個過程中,IPython 可以用來查看函數(shù)的文檔,測試如何調(diào)用某些函數(shù),看看返回值是什么樣子等等,還是跟上面的說的一樣,我們有一個動態(tài)的環(huán)境可以真真正正的執(zhí)行程序,你可以 在把代碼寫到你珍貴的主程序之前就有機(jī)會運(yùn)行它,這樣你可以更確認(rèn)你的代碼能正常工作:

In [4]: s="foo"# 忘記判斷字符串是數(shù)字的函數(shù)的名字了,用一個字符串試試看

In [5]: s.is# 開頭大概是 is,這里按下 tab 鍵 IPython 會幫我們補(bǔ)全

s.isalnum? s.isalpha? s.isdigit? s.islower? s.isspace? s.istitle

In [6]: s.isdigit?# 結(jié)果是 isdigit,在表達(dá)式后加上問號并回車查看文檔

Type:?????? builtin_function_or_method

String Form:

Docstring:

S.isdigit()->bool

ReturnTrueifallcharactersinS are digits

andthereisat least one characterinS,Falseotherwise.

In [8]: s.isdigit()# 調(diào)用試試看

Out[8]:False

In [9]:'f'in'foo'# 試試字符串能不能用 in 來判斷

Out[9]:True

確認(rèn)了各個步驟以后,我們把 lexer 的代碼填起來。我們?yōu)榱斯?jié)省縱向的空間我們把很多東西寫在一行里面:

# simple math expression parser (broken lexer)

deflexer(s):

'''token generator'''

ix=0

whileix

ifs[ix].isspace(): ix+=1

ifs[ix]in"+-*/()":

yields[ix]; ix+=1

ifs[ix].isdigit():

jx=ix+1

whilejx

yields[ix:jx]; ix=jx

else:

raiseException("invalid char at %d: '%s'"%(ix, s[ix]))

yield""

if__name__=='__main__':

printlist(lexer("1 + (2 - 3) * 456"))

看起來不錯,我們還是在 IPython 里執(zhí)行試試,結(jié)果發(fā)現(xiàn)程序拋出了一個異常:

In [6]: run expr.py

------------------------------------------------------------------

Exception?????????????????????? Traceback (most recent call last)

py/expr.pyin()

if__name__=='__main__':

--->20printlist(lexer("1 + (2 - 3) * 456"))

py/expr.pyinlexer(s)

yields[ix:jx]; ix=jx

else:

--->raiseException("invalid character at ...))

yield""

Exception: invalid character at3:' '

嗯?好像程序里已經(jīng)處理了空格的情況。怎么會這樣?不知道你碰到異常的時候一般都怎么辦。你可能會選擇到處添加print,用 IDE 斷點(diǎn)調(diào)試。其實(shí)這種情況用pdb是很明智的選擇,在 IPython 里我們可以非常輕松的使用它。

In [13]: pdb# 開啟 pdb ,這樣在異常的時候我們會自動的 break 到異常處

Automatic pdb calling has been turned ON

In [14]: run expr.py

-----------------------------------------------------------------

Exception: invalid character at3:' '

> py/expr.py(15)lexer()

else:

--->raiseException("invalid char at ...))

yield""

ipdb>printix# 這里我們可以執(zhí)行任何 Python 的代碼


ipdb> whatis ix# 也可以用 pdb 提供的命令,輸入 help 可以查看所有命令

通過方便的調(diào)試和仔細(xì)檢查代碼,我們發(fā)現(xiàn)是沒有正確的使用elif造成了問題!(我知道這個過程不是太符合情理...)。把代碼里的后面的幾個if都換成elif以后我們發(fā)現(xiàn)結(jié)果基本上是對的了。我們可以馬上再跑幾個類似的例子,確認(rèn)不同的輸入是否都有比較好的結(jié)果:

In [18]: run expr.py# 這次差不多對了,我們可以試試幾個別的例子

['1','+','(','2','-','3',')','*','456', '']

In [19]:printlist(lexer("1*123*87-2*5"))

['1','*','123','*','87','-','2','*','5', '']

# 跟在 shell 里面一樣,你可以用上下來選取之前的記錄,然后簡單的修改再重新執(zhí)行。

# 記得每次 run 后你的函數(shù)都是最新版本,你可以很簡單的用重復(fù)的數(shù)據(jù)來測試你的函數(shù)

# IPython 甚至還實(shí)現(xiàn)了 Ctrl+R!自己試試看吧

In [19]:printlist(lexer("1 + two"))

Exception: invalid character at2:'t'...

在一段痛苦的調(diào)試之后,我們最終把程序寫出來了。很遺憾程序超出了我預(yù)計的長度,就不貼在這里了。后面部分的開發(fā)過程跟前面基本還是一樣,總結(jié)起來就是:

保持你的程序是一個可以運(yùn)行并且有意義的狀態(tài),盡可能頻繁的運(yùn)行。

在 IPython 里查看文檔,嘗試小的程序片段,測試些你不確定的做法,確定之后再把東西添加到你的代碼里。

用不同的參數(shù)在 IPython 里測試你正在編寫的函數(shù)/class。

當(dāng)遇到問題的時候,先簡單的用pdb在異常處 break,十有八九都能有些頭緒。

額外的注意事項

這里舉的例子是你所有的開發(fā)都是在單個.py文件里的?,F(xiàn)實(shí)生活中你很有可能會橫跨幾個文件一起修改。請務(wù)必注意,在 IPython 里你每次run的時候只有被run的那個文件里的東西會是最后修改的版本,其import的東西如果在期間被修改是不會反應(yīng)出來的。

這個的原理就跟你在 Python shell 里在修改前修改后重復(fù)import某個模塊不會有作用是一樣的,Python 神奇的import機(jī)制不會去追蹤其他模塊的修改。你可以手動用reload函數(shù)來重新載入,你也可以使用 IPython 的autoreload功能來讓你忽略這個問題。個人來說我沒怎么用過這個功能,IPython 沒有默認(rèn)開啟它可能也是有些顧慮,請自己評估看看。

另外你應(yīng)該已經(jīng)注意到,run的效果基本上就是把你的代碼拷貝進(jìn) IPython 里執(zhí)行一遍。對于沒有__main__的文件,你也可以run,這樣里面定義的函數(shù)和 class 就會反映出你的更改。

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

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

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