PrettyPrinter是Python 3.6 及以上版本中的一個(gè)功能強(qiáng)大、支持語(yǔ)法高亮、描述性的美化打印包。它使用了改進(jìn)的Wadler-Leijen布局算法,和Haskell打印美化庫(kù)中的prettyprinter以及anti-wl-pprint、 JavaScript的Prettier、Ruby的prettypreinter.rb 以及 IPython的Ipython.lib.pretty類似。Python的PrettyPrinter集以上眾家之所長(zhǎng),并在此基礎(chǔ)上繼續(xù)改進(jìn),因此也成為目前Python最強(qiáng)大的美化輸出工具。
以下是使用PrettyPrinter輸出結(jié)果的截圖:
為什么Python還需要額外的美化打印包呢?
無(wú)論是IDE還是開發(fā)者手動(dòng)運(yùn)行命令,將數(shù)據(jù)打印到屏幕上是程序運(yùn)行過(guò)程中程序員和數(shù)值交互的最基礎(chǔ)的界面。改進(jìn)該界面有助于提升開發(fā)體驗(yàn)和生產(chǎn)效率。Python本身和第三方庫(kù)都提供了一些工具來(lái)達(dá)到此目的:
__repr__和__str__兩個(gè)下劃線方法返回普通字符串。__repr__應(yīng)該盡可能返回語(yǔ)法正確的Python表達(dá)式,斷言判斷失敗及控制臺(tái)計(jì)算結(jié)果打印最常用的就是該方法。由于其完全基于字符串格式化,因此并不具備美化打印的功能。
標(biāo)準(zhǔn)庫(kù)中的pprint模塊為dicts, lists, tuples, sets, and frozensets等內(nèi)置數(shù)據(jù)類型提供了美化打印的功能。它將__repr__方法應(yīng)用在用戶自定義的類實(shí)例上。然而,它使用了非常貪婪的布局算法,導(dǎo)致在很多情況下的美化打印出現(xiàn)問(wèn)題。由于自定義的美化打印受__repr__所限制,pprint的作用也就限制于內(nèi)置數(shù)據(jù)類型了。
第三方庫(kù)pprintpp是對(duì)pprint的改進(jìn)及替代方案,也可以對(duì)輸出進(jìn)行優(yōu)化,不過(guò)和pprint一樣受限于__repr__使用的代碼美化定義。
IPython中默認(rèn)的打印模塊IPython.lib.pretty的目標(biāo)是pprint更進(jìn)階的替代方案。和pprint相比,它在很多方面都表現(xiàn)得更好:大多數(shù)情況下算法都能對(duì)輸出進(jìn)行美化,而且提供了針對(duì)用戶自定義類型美化輸出的定義工具,能和輸出的其他部分實(shí)現(xiàn)比較好的結(jié)合。不過(guò),為了實(shí)現(xiàn)你自己的美化打印方式,你需要對(duì)布局算法有所了解。另外,該API 也有一些與生俱來(lái)的副作用:調(diào)用美化打印工具將數(shù)據(jù)直接推送至布局緩沖區(qū),不允許原始布局對(duì)數(shù)據(jù)進(jìn)行初步檢測(cè)。
以上所有工具都達(dá)不到我對(duì)美化打印體驗(yàn)的要求,因此我開始做以下幾點(diǎn)改進(jìn):
實(shí)現(xiàn)一個(gè)能盡可能多的美化打印的算法,即便在效率上做出一些犧牲?;ㄊ种幻雽?duì)輸出結(jié)果進(jìn)行美化是非常劃算的,因?yàn)楫?dāng)你需要在結(jié)果中尋找自己需要的數(shù)據(jù)時(shí)它將為你節(jié)約兩秒鐘的時(shí)間。
實(shí)現(xiàn)一個(gè)超級(jí)簡(jiǎn)單、描述性的接口來(lái)實(shí)現(xiàn)用戶自定義的美化打印工具。Python成員幾乎不會(huì)重寫__repr__方法,因?yàn)檫@很痛苦;幾乎沒(méi)有人愿意為用戶定義的類型編寫整齊打印規(guī)則,除非類型非常簡(jiǎn)單。
實(shí)現(xiàn)不會(huì)在無(wú)效Python語(yǔ)法上中斷的語(yǔ)法高亮顯示。并不是所有__repr__方法都會(huì)返回有效的語(yǔ)法,一旦發(fā)生語(yǔ)法錯(cuò)誤會(huì)打斷正常的語(yǔ)法高亮。
新的代碼美化包的使用體驗(yàn)令我非常驚訝。算法運(yùn)行的很出色,效率也滿足需求。而用戶自定義美化規(guī)則的方法也很簡(jiǎn)單,僅僅需要了解兩個(gè)描述性的函數(shù) register_pretty和pretty_call即可。語(yǔ)法高亮看上去非常漂亮,且不會(huì)被無(wú)效語(yǔ)法處中斷。特別是語(yǔ)法高亮,會(huì)使你很難再回到普通的美化打印工具,它大大提升了程序員的開發(fā)體驗(yàn)。
最有趣的改進(jìn)是描述性API,下面是它的工作原理。
簡(jiǎn)單、描述性的API
在PrettyPrinter中定義輸出美化方法主要基于(創(chuàng)建)函數(shù)調(diào)用。所有非字符的Python值都需要用函數(shù)結(jié)果表示。該庫(kù)的主力函數(shù)是pretty_call, 它允許你來(lái)描述PrettyPrinter應(yīng)該輸出何種類型的函數(shù)調(diào)用。下面就是pretty_call調(diào)用的一個(gè)例子:
PrettyPrinter處理原始布局的過(guò)程類似于以下語(yǔ)句:
(第一個(gè)參數(shù)ctx允許用戶控制案例中[5,3,6,1]列表中嵌套的數(shù)據(jù),reverse參數(shù)的True值依據(jù)此進(jìn)行渲染。大部分情況都直接使用默認(rèn)值即可。)
上面介紹了如何使用Pretty_call,接下來(lái)定義我們自己的類型。
使用register_pretty修飾符,可以為MyClass類定義美化方式:
cpprint的輸出如下:
點(diǎn)擊the PrettyPrinter definition code for standard library types,查看更多案例。
帶狀態(tài)實(shí)例的表示
調(diào)用函數(shù)的一個(gè)缺陷是無(wú)法很好的表示帶狀態(tài)的實(shí)例。通常你想要額外輸出一些信息來(lái)表示實(shí)例的狀態(tài)。PrettyPrinter使用解釋性評(píng)論解決了這一問(wèn)題,我對(duì)這一強(qiáng)大的特性頗為滿意。使用評(píng)論來(lái)標(biāo)注Python值(或者表示Python值的原始布局),該評(píng)論將神奇的出現(xiàn)在輸出的結(jié)果中。
假如我們定義了一個(gè)包含其連接與斷開兩個(gè)狀態(tài)的Connection類:
如果想得到以下輸出:
可以通過(guò)如下定義來(lái)實(shí)現(xiàn):
結(jié)論
我非常享受將PrettyPrinter作為開發(fā)工具包的一部分。單獨(dú)一篇文章只能粗略分享一些點(diǎn),還有很多有趣的部分等待你去探索,強(qiáng)烈推薦大家嘗試一下!在IPython中使用效果更佳,因?yàn)榻换ナ浇忉屍鳝h(huán)境中的所有結(jié)果都可以自動(dòng)使用PrettyPrinter打印輸出。文檔中有對(duì)該命令的設(shè)置的說(shuō)明。
點(diǎn)擊source code on GitHub查看該項(xiàng)目的源碼,文檔在documentation on readthedocs.io(目前可能還略顯簡(jiǎn)陋)。包中內(nèi)置了針對(duì)Django模型、QuerySets以及使用attrs包創(chuàng)建的所有類的現(xiàn)成的定義。因此如果你恰好也用到了其中的某個(gè),毫無(wú)疑問(wèn)你會(huì)想馬上試試它的!
-
API
+關(guān)注
關(guān)注
2文章
1472瀏覽量
61749 -
IDE
+關(guān)注
關(guān)注
0文章
334瀏覽量
46614 -
python
+關(guān)注
關(guān)注
55文章
4767瀏覽量
84375
原文標(biāo)題:讓Python輸出更漂亮:PrettyPrinter
文章出處:【微信號(hào):magedu-Linux,微信公眾號(hào):馬哥Linux運(yùn)維】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論