歡迎光臨
每天分享高質量文章

讓Python輸出更漂亮:PrettyPrinter

PrettyPrinter是Python 3.6 及以上版本中的一個功能強大、支援語法高亮、描述性的美化列印包。它使用了改進的Wadler-Leijen佈局演演算法,和Haskell列印美化庫中的prettyprinter以及anti-wl-pprint、 JavaScript的Prettier、Ruby的prettypreinter.rb 以及 IPython的Ipython.lib.pretty類似。Python的PrettyPrinter集以上眾家之所長,併在此基礎上繼續改進,因此也成為目前Python最強大的美化輸出工具。

以下是使用PrettyPrinter輸出結果的截圖:

為什麼Python還需要額外的美化列印包呢?

無論是IDE還是開發者手動執行命令,將資料列印到螢幕上是程式執行過程中程式員和數值互動的最基礎的介面。改進該介面有助於提升開發體驗和生產效率。Python本身和第三方庫都提供了一些工具來達到此目的:

  • __repr____str__兩個下劃線方法傳回普通字串。__repr__應該盡可能傳回語法正確的Python運算式,斷言判斷失敗及控制檯計算結果列印最常用的就是該方法。由於其完全基於字串格式化,因此並不具備美化列印的功能。

  • 標準庫中的pprint模組為dicts, lists, tuples, sets, and frozensets等內建資料型別提供了美化列印的功能。它將__repr__方法應用在使用者自定義的類實體上。然而,它使用了非常貪婪的佈局演演算法,導致在很多情況下的美化打印出現問題。由於自定義的美化列印受__repr__所限制,pprint的作用也就限制於內建資料型別了。

  • 第三方庫pprintpp是對pprint的改進及替代方案,也可以對輸出進行最佳化,不過和pprint一樣受限於__repr__使用的程式碼美化定義。

  • IPython中預設的列印模組IPython.lib.pretty的標的是pprint更進階的替代方案。和pprint相比,它在很多方面都表現得更好:大多數情況下演演算法都能對輸出進行美化,而且提供了針對使用者自定義型別美化輸出的定義工具,能和輸出的其他部分實現比較好的結合。不過,為了實現你自己的美化列印方式,你需要對佈局演演算法有所瞭解。另外,該API 也有一些與生俱來的副作用:呼叫美化列印工具將資料直接推送至佈局緩衝區,不允許原始佈局對資料進行初步檢測。

以上所有工具都達不到我對美化列印體驗的要求,因此我開始做以下幾點改進:

  • 實現一個能盡可能多的美化列印的演演算法,即便在效率上做出一些犧牲。花十分之一秒對輸出結果進行美化是非常划算的,因為當你需要在結果中尋找自己需要的資料時它將為你節約兩秒鐘的時間。

  • 實現一個超級簡單、描述性的介面來實現使用者自定義的美化列印工具。Python成員幾乎不會重寫__repr__方法,因為這很痛苦;幾乎沒有人願意為使用者定義的型別編寫整齊列印規則,除非型別非常簡單。

  • 實現不會在無效Python語法上中斷的語法高亮顯示。並不是所有__repr__方法都會傳回有效的語法,一旦發生語法錯誤會打斷正常的語法高亮。

新的程式碼美化包的使用體驗令我非常驚訝。演演算法執行的很出色,效率也滿足需求。而使用者自定義美化規則的方法也很簡單,僅僅需要瞭解兩個描述性的函式 register_pretty和pretty_call即可。語法高亮看上去非常漂亮,且不會被無效語法處中斷。特別是語法高亮,會使你很難再回到普通的美化列印工具,它大大提升了程式員的開發體驗。

最有趣的改進是描述性API,下麵是它的工作原理。

簡單、描述性的API

在PrettyPrinter中定義輸出美化方法主要基於(建立)函式呼叫。所有非字元的Python值都需要用函式結果表示。該庫的主力函式是pretty_call, 它允許你來描述PrettyPrinter應該輸出何種型別的函式呼叫。下麵就是pretty_call呼叫的一個例子:

PrettyPrinter處理原始佈局的過程類似於以下陳述句:

(第一個引數ctx允許使用者控制案例中[5,3,6,1]串列中巢狀的資料,reverse引數的True值依據此進行渲染。大部分情況都直接使用預設值即可。)

上面介紹瞭如何使用Pretty_call,接下來定義我們自己的型別。

使用register_pretty修飾符,可以為MyClass類定義美化方式:

cpprint的輸出如下:

點選 the PrettyPrinter definition code for standard library types,檢視更多案例。

帶狀態實體的表示

呼叫函式的一個缺陷是無法很好的表示帶狀態的實體。通常你想要額外輸出一些資訊來表示實體的狀態。PrettyPrinter使用解釋性評論解決了這一問題,我對這一強大的特性頗為滿意。使用評論來標註Python值(或者表示Python值的原始佈局),該評論將神奇的出現在輸出的結果中。

假如我們定義了一個包含其連線與斷開兩個狀態的Connection類:

如果想得到以下輸出:

可以透過如下定義來實現:

結論

我非常享受將PrettyPrinter作為開發工具包的一部分。單獨一篇文章只能粗略分享一些點,還有很多有趣的部分等待你去探索,強烈推薦大家嘗試一下!在IPython中使用效果更佳,因為互動式直譯器環境中的所有結果都可以自動使用PrettyPrinter列印輸出。檔案中有對該命令的設定的說明。

點選source code on GitHub檢視該專案的原始碼,檔案在documentation on readthedocs.io(目前可能還略顯簡陋)。包中內建了針對Django模型、QuerySets以及使用attrs包建立的所有類的現成的定義。因此如果你恰好也用到了其中的某個,毫無疑問你會想馬上試試它的!

英文原文:https://tommikaikkonen.github.io/introducing-prettyprinter-for-python/
譯者:woody


《Python人工智慧和全棧開發》2018年07月23日即將在北京開課,120天衝擊Python年薪30萬,改變速約~~~~

*宣告:推送內容及圖片來源於網路,部分內容會有所改動,版權歸原作者所有,如來源資訊有誤或侵犯權益,請聯絡我們刪除或授權事宜。


– END –


更多Python好文請點選【閱讀原文】哦

↓↓↓

贊(0)

分享創造快樂