一但習慣某個東西的好處後, 久了就會忘了它的重要性。今天重操舊業寫了久違的 python, 覺得能用 python 寫程式已很爽了, 還能用 ipython 寫 python, 更是爽上加爽!特此記錄一下, 分享給還未試過的人。
ipython 是 python 的互動式 shell, 功能相當強大, 而且預設設定就相當好用。如今 ipython 已發展到令人難以想像的地步, 以下只是基本的使用情境。
試用別人的模組
$ ipython Python 2.7.3 (default, Aug 1 2012, 05:14:39) Type "copyright", "credits" or "license" for more information. IPython 0.13.1 -- An enhanced Interactive Python. ? -> Introduction and overview of IPython's features. %quickref -> Quick reference. help -> Python's own help system. object? -> Details about 'object', use 'object??' for extra details. In [1]: import os In [2]: os.pa<TAB> os.pardir os.pathconf os.pathsep os.path os.pathconf_names In [2]: os.path.join? Type: function String Form:<function join at 0x7f67f9c09ed8> File: /usr/lib/python2.7/posixpath.py Definition: os.path.join(a, *p) Docstring: Join two or more pathname components, inserting '/' as needed. If any component is an absolute path, all previous path components will be discarded. In [3]: os.path.join('a', 'b') Out[3]: 'a/b' In [4]: os.path.join?? Type: function String Form:<function join at 0x7f67f9c09ed8> File: /usr/lib/python2.7/posixpath.py Definition: os.path.join(a, *p) Source: def join(a, *p): """Join two or more pathname components, inserting '/' as needed. If any component is an absolute path, all previous path components will be discarded.""" path = a for b in p: if b.startswith('/'): path = b elif path == '' or path.endswith('/'): path += b else: path += '/' + b return path
首先我先 import os, 第二行打了 os.pa<TAB> 看看有那些名稱開頭為 "pa" 的子物件或函式可用。也可以用 os.<TAB> 看 os 下的全部物件和函式。
接著找到 os.path.join, 在它後面加上 "?", 表示想知道 os.path.join 的 python doc。了解用法後就在第三行試試, ipython 預設會輸出 expression 回傳的結果 (而且是用 pretty-print 的方式呈現)。
最後第四行用 "??" 查詢 os.path.join 的實作, 有時沒有文件或看不懂文件的話, 直接看原始碼也滿方便的。另外讀別人程式發覺 import module 順序太複雜時, 也可以先用 ipython import 進來, 再用 "??" 看最後 import 到的是那一份實作。也可從裡面提到的檔名再用編輯器打開來看。
有了 <TAB>、? 和 ?? 後, 不太需要從外部找參考手冊, 直接在 ipython 裡試比較快。
開發片段小程式
試了一些片段小程式, 了解怎麼使用別人的模組後, 再來會想拼湊一些小程式。這時可用 edit 進入編輯器 (會選用環境變數 EDITOR 設的值):
In [1]: edit IPython will make a temporary file named: /tmp/ipython_edit_bAOgl9.py Editing... done. Executing edited code... Out[1]: 'class Rect(object):\n def __init__(self, x, y, w, h):\n self.x = x\n self.y = y\n self.w = w\n self.h = h\n' In [2]: r = Rect(0, 0, 100, 50) In [3]: r.w Out[3]: 100 In [4]: r.area() --------------------------------------------------------------------------- AttributeError Traceback (most recent call last) <ipython-input-8-83a71df0c49c> in <module>() ----> 1 r.area() AttributeError: 'Rect' object has no attribute 'area' In [5]: edit -p IPython will make a temporary file named: /tmp/ipython_edit_stFwGi.py Editing... done. Executing edited code... Out[5]: 'class Rect(object):\n def __init__(self, x, y, w, h):\n self.x = x\n self.y = y\n self.w = w\n self.h = h\n\n def area(self):\n return self.w * self.h\n' In [6]: r2 = Rect(0, 0, 100, 50) In [7]: r2.area() Out[7]: 5000
在第一行按 edit 後, 畫面會切到編輯器, 寫好內容存檔離開後, ipython 會載入剛才打的內容到 ipython 裡, 也就是第一行輸出 'class Rect(object):\n def __init__ ...' 那一串。這裡我定義了 class Rect, 然後試一下 Rect 看看有沒有寫錯。接著第五行 edit -p 表示回去編輯上一次的內容, 執行後一樣會進入編輯器, 不過內容會先有上一次打過的東西。這回我多補了 area() 函式, 於是新增的 Rect 物件就有這函式了。
拼湊差不多後, 可用 edit -p 取得內容, 另外存到檔案, 或是打 hist 看打過的內容, 手動剪貼到檔案裡。
開發完整程式
想法明確時, 直接用編輯器編寫, 再輔以 ipython 測試更有效率。
首先, 終端機A的編輯器畫面如下所示, 寫了一個階乘函數:
# foo.py def factorial(n): s = 1 for i in range(n): s *= i return s
然後在終端機B的 ipython 測試:
In [1]: import foo In [2]: foo.factorial(3) Out[2]: 0 In [3]: reload(foo) Out[3]: <module 'foo' from 'foo.py'> In [4]: foo.factorial(3) Out[4]: 6
第二行測完發覺結果不對, 於是回終端機A修改, 將 range(n) 改為 range(1, n + 1), 再回來終端機B執行 reload(foo) 重新載入 foo。接著第四行重測就得到正確的結果了。
當然, 發覺結果不對時, 也可以在 ipython 測測 range() 的用法, 或用 range? 看看說明, 很快就會找到答案。
結語
以上只是基本的 ipython 用途, 相信開發速度已可以比單用編輯器寫 python 快上兩倍以上。強烈建議有寫 python 的人一定要用看看 ipython。
ipython notebook可以直接內嵌 可互動graph、網頁、video才是酷:
回覆刪除http://ipython.org/notebook.html