如何美觀地列印 Python 物件?這個標準庫可以簡單實現
前不久,我寫了一篇文章回顧 Python 中 print 的發展歷史 ,提到了兩條發展線索:
- 明線:早期的 print 語句帶有 C 和 Shell 的影子,是個應用程式級的 statement,在最初十幾年裡,經歷過 PEP-214 和 PEP-259 的改進;再到 2009 年的大版本 3.0,由語句改成了 print() 函式,還在 3.3 版本,做過一次功能增強,最終上升成為一等的內建函式。
- 暗線:介紹了 print 的競爭對手們,像傳統的日誌模組 logging、除錯模組 pdb、主流 IDE 的除錯功能,以及後起之秀 PySnooper,它們瞄準著 print 的位置,摩拳擦掌,虎視眈眈。
本文依然跟 print 相關,想介紹的是標準庫中的 pprint
模組。
(未經授權,請勿轉載。文章首發於:https://mp.weixin.qq.com/s/d1dQH1Fqaj_U3AXKYluhSw)
pprint 是“pretty printer”的簡寫,“pretty”的含義是“漂亮的、美觀的”,還有表示“相當地”的程度語氣,因此它的含義便是:(相當)美觀的列印。
這是個相當簡單卻有用的模組,主要用於列印複雜的資料結構物件,例如多層巢狀的列表、元組和字典等。
先看看 print() 列印的一個例子:
mylist = ["Beautiful is better than ugly.", "Explicit is better than implicit.", "Simple is better than complex.", "Complex is better than complicated."] print(mylist) # 結果如下: ['Beautiful is better than ugly.', 'Explicit is better than implicit.', 'Simple is better than complex.', 'Complex is better than complicated.']
這是一個簡單的例子,全部列印在一行裡。
想象一下,如果物件中的元素是多層巢狀的內容(例如複雜的 Json 資料),或者有超多的元素(例如在列表中存了很多 URL 連結),再打印出來會是怎樣?
那肯定是一團糟的,不好閱讀。
使用 pprint 模組的 pprint() 替代 print(),可以解決如下痛點:
- 設定合適的行寬度,作適當的換行
- 設定列印的縮排、層級,進行格式化列印
- 判斷物件中是否出現無限迴圈,並優化列印內容
1、簡單使用
語法:pprint(object, stream=None, indent=1, width=80, depth=None, *,compact=False)
預設的行寬度引數為 80,當列印的字元(character)小於 80 時,pprint() 基本上等同於內建函式 print(),當字元超出時,它會作美化,進行格式化輸出:
import pprint
# 列印上例的 mylist
pprint.pprint(mylist)
# 列印的元素是換行的(因為超出80字元):
['Beautiful is better than ugly.',
'Explicit is better than implicit.',
'Simple is better than complex.',
'Complex is better than complicated.']
2、設定縮排為 4 個空格(預設為1)
pprint.pprint(mylist, indent=4)
[ 'Beautiful is better than ugly.',
'Explicit is better than implicit.',
'Simple is better than complex.',
'Complex is better than complicated.']
3、設定列印的行寬
mydict = {'students': [{'name':'Tom', 'age': 18},{'name':'Jerry', 'age': 19}]}
pprint.pprint(mydict)
# 未超長:
{'students': [{'age': 18, 'name': 'Tom'}, {'age': 19, 'name': 'Jerry'}]}
pprint.pprint(mydict, width=20)
# 超長1:
{'students': [{'age': 18,
'name': 'Tom'},
{'age': 19,
'name': 'Jerry'}]}
pprint.pprint(mydict, width=70)
# 超長2:
{'students': [{'age': 18, 'name': 'Tom'},
{'age': 19, 'name': 'Jerry'}]}
4、設定列印的層級(預設全列印)
newlist = [1, [2, [3, [4, [5]]]]]
pprint.pprint(newlist, depth=3)
# 超出的層級會用...表示
[1, [2, [3, [...]]]]
5、優化迴圈結構的列印
當列表或其它資料結構中出現迴圈引用時,要完整打印出所有內容是不可能的。
所以 print 作了簡化處理,就像上例一樣,只打印外層的殼,而不列印內層迴圈的東西。
這種處理方式是簡化了,但沒有指出是誰導致了迴圈,還容易看漏。
pprint() 方法作了改進,遇到無限迴圈結構時,會表示成<Recursion on typename with id=number>
的格式。
還有個 saferepr() 方法,也是這樣優化,而且返回的是個字串:
newlist = [1, 2]
newlist.insert(0, newlist)
# 列表元素指向列表自身,造成迴圈引用
# 直接 print 的結果是:[[...], 1, 2]
pprint.pprint(newlist)
# [<Recursion on list with id=1741283656456>, 1, 2]
pprint.saferepr(newlist)
# '[<Recursion on list with id=1741283656456>, 1, 2]'
6、判斷是否出現迴圈結構
有兩個方法可以判斷一個物件中是否出現無限迴圈:
pprint.isrecursive(newlist)
# True
pprint.isreadable(newlist)
# False
isreadable() 除了能像 isrecursive() 一樣判斷迴圈,還能判斷該格式化內容是否可被 eval() 重構。
以上就是 pprint 模組的快捷入門介紹,除此之外,還有 pformat() 方法、PrettyPrinter 類,以及某些引數的使用等內容,我覺得沒有大用,就不多說了。
如若感興趣,你可查閱:
- 官方介紹:https://docs.python.org/zh-cn/3/library/pprint.html
- 原始碼地址:https://github.com/python/cpython/blob/3.7/Lib/pprint.py
最後,還有兩個小小的點:
1、用 pprint() 替換 print() 的技巧
在不考慮 print() 函式本身的引數的情況下,可以在引入 pprint 模組後,寫上 “print = pprint.pprint”,令 print() 起到改頭換面的效果:
import pprint
print = pprint.pprint
mylist = ["Beautiful is better than ugly.", "Explicit is better than implicit.", "Simple is better than complex.", "Complex is better than complicated."]
print(mylist)
# 可對比本文開頭的例子
['Beautiful is better than ugly.',
'Explicit is better than implicit.',
'Simple is better than complex.',
'Complex is better than complicated.']
2、國人開發的 beeprint
國內某位 pan 同學在 Github 開源了個beeprint
,明顯是對標 pprint
的。
專案地址:https://github.com/panyanyany/beeprint
它優化了字典物件的列印,對於從其它語言轉過來的同學而言(例如 Java),這是個福音:
它還優化了長文字的列印,支援自定義物件的列印,看起來不錯。
但是,其它功能不夠齊全,而且作者停止維護兩年了,荒廢已久……
總體而言,pprint 算是 print() 的輕量級替代,簡單實用,極其方便(畢竟是標準庫),文件豐富而有保障。
所以,若想要列印美觀易讀的資料,這個 pprint 標準庫,不妨一試哦。
作者簡介:豌豆花下貓,生於廣東畢業於武大,現為蘇漂程式設計師,有一些極客思維,也有一些人文情懷,有一些溫度,還有一些態度。公眾號:「Python貓」(python_cat)
公眾號【Python貓】, 本號連載優質的系列文章,有喵星哲學貓系列、Python進階系列、好書推薦系列、技術寫作、優質英文推薦與翻譯等等,歡迎關注哦