Python 中 6 款 JSON 庫的全方位盤點!
原文地址:JSON encoding/decoding with Python 原文作者:Martin Thoma 譯文出自:掘金翻譯計劃 本文永久鏈接:https://github.com/xitu/gold-miner/blob/master/article/2021/json-encoding-decoding-with-python.md 譯者:洛竹、雪刺
REST API 是 在全世界使用標(biāo)準(zhǔn)化的消息格式。JSON 是互聯(lián)網(wǎng)上數(shù)據(jù)交換的基石,作為 JavaScript 的一個子集,它從一開始就獲得了巨大的推廣。它特別清晰易讀的語法也有利于推廣。
據(jù)我所知各種語言都有 JSON 庫用于序列化和反序列化。實際上在 Python 中就有很多種 JSON 庫。在下文中,我將為大家比較它們的異同。
引用庫
CPython 本身具有一個 json 模塊。它最初是由 Bob Ippolito 作為 simplejson 開發(fā)的,并被合并到 Python 2.4 中(源代碼)。CPython 遵循 Python 軟件基金會(Python Software Foundation)許可協(xié)議。
simplejson 仍然作為一個單獨的庫存在,你可以通過 pip 安裝它。它是帶有可選 C 擴展的純 Python 庫。Simplejson 遵循 MIT 和 Academic Free License(AFL)許可協(xié)議。
ujson 是對 C 語言庫 Ultra JSON 的綁定。Ultra JSON 由 ESN(一家電子藝術(shù)工作室公司)開發(fā),并獲得了 3條款BSD許可。Ultra JSON 在 Github 上擁有 3k 星,305 個 fork,50 個貢獻者,最近一次提交的日期只有 12 天,而最后一次提交是在 5 天之前發(fā)布的。我聽說它處于“維護模式”(來源),表明沒有新的進展。
pysimdjson 是對 C ++ 庫 simdjson 的綁定。SIMDjson 從加拿大獲得資助。simdjson 在 Github 上有 12.2k 顆星,611 個分支,63 個貢獻者,最后一次提交是 11 小時前,而最后一個 issue 是 2 小時前創(chuàng)建的。
python-rapidjson 是對 C ++ 庫 RapidJSON 的綁定。RapidJSON 由 騰訊 開發(fā)。RapidJSON 在 GitHub 上有 9.8k 個星,2.7k 個 fork,150 個貢獻者,最近一次提交大約在 2 個月前,而最后一個 issue 是 17 天前創(chuàng)建的。
orjson 是一個 Python 軟件包,依靠 Rust 來完成繁重的工作。
成熟度和操作安全性
上面所有提到的庫都可以毫無問題地用作 benchmark 示例,切換 JSON 模塊也不是什么大問題,但我仍然想確定相關(guān)模塊是否支持。
CPython,simplejson,ujson 和 orjson 都認(rèn)為他們自己已經(jīng)可以投產(chǎn)了。
python-rapidjson 將自身標(biāo)記為 alpha,但是一位維護人員說這是一個錯誤,并將很快得到修復(fù)(資源)。

問題
判斷一個庫的問題是否能夠被順利解決,一個直接的方式是直接去它的倉庫創(chuàng)建 issue,并觀察后續(xù)的跟進反饋:
SimpleJSON:第二天我得到了答復(fù),回答很明確,易于理解,友善。Bob Ippolito 回答了我。他是最初開發(fā)這個庫的人,并且在 JSON 模塊的 Python 文檔中也提到了他! uJSON:30分鐘內(nèi),我得到了一個清晰,友好,易于遵循的答案。@hugovank ORJSON:10天沒有反應(yīng),然后關(guān)閉,沒有任何評論。 [PySIMDJSON]:15天后無人答復(fù)。 Python-RapidJSON:在30分鐘內(nèi),我得到了一個清晰,友好,易于遵循的答案。十天后合并了一個簡單的PR。
通過以上操作我得出一個答案,它們基本上沒有相互關(guān)系。
基準(zhǔn)測試(Benchmark)
為了正確地對不同的庫進行基準(zhǔn)測試,我考慮了以下情況:
API:交換信息的 Web 服務(wù)。它可能包含 Unicode 并具有嵌套結(jié)構(gòu)。Twitter API 的 JSON 文件聽起來不錯,可以對此進行測試。 API JSON錯誤:我很好奇如果 JSON API 格式有錯誤,性能會如何變化。因此,我在中間刪除了一個大括號。 GeoJSON:我首先通過一個開源街道地圖導(dǎo)出器 Overpass Turbo 得到了 GeoJSON 格式的 JSON 文件。你將獲得瘋狂多的 JSON 文件,這些文件大多具有坐標(biāo),而且還很嵌套。 機器學(xué)習(xí):只是大量的浮點數(shù)列表。這些可能是神經(jīng)網(wǎng)絡(luò)層的權(quán)重。 JSON行:結(jié)構(gòu)化日志在行業(yè)中大量使用。如果分析這些日志,可能需要遍歷千兆字節(jié)的數(shù)據(jù)。它們都是帶有日期時間對象、消息、記錄器、日志狀態(tài)等信息的簡單字集。
反序列化速度
我將我的硬盤驅(qū)動器的讀取速度設(shè)置了一個較低的上限,在以下3個圖表中將以它作為基準(zhǔn)。





由此得出的結(jié)論是:
Rapidjson 速度很慢,但是對于像 twitter.json 這樣的小型 JSON,你不會注意到有什么不同。可以通過結(jié)構(gòu)化日志看到這一點。 simdjson,orjson 和 ujson 都快得驚人。 對于大多數(shù)庫而言,讀取包含結(jié)構(gòu)錯誤的 JSON 文件的速度相同。一個值得注意的例外是 Rapidjson。我猜一旦發(fā)現(xiàn)錯誤,它將中止讀取文件。
序列化速度
在這里,我預(yù)先創(chuàng)建了 JSON 字符串,并以寫入磁盤的時間作為基線測量了所需的時間。




我由此得出的結(jié)論是:
orjson 非???,超級接近我的硬盤驅(qū)動器寫入速度。ujson 也非常接近。 Rapidjson 也很快,但與 orjson 或 ujson 不在同一級別。 simdjson 很慢。
專業(yè)的 JSON 工作流
最后總結(jié)一下,我想指出一些我之前看到并記錄下來的問題:
調(diào)用變量
foo_json:JSON 是一種字符串格式。如果不是字符串,則不是 JSON。如果使用bar = json.loads(foo)反序列化 JSON,則 bar 不是 JSON。你可以將 bar 序列化為與 JSON
foo等效的 JSON,但 bar 不是 JSON,這是一個 Python 對象,很像一個字典對象,就將它當(dāng)作foo_json。屬性會在各處進行檢查:如果你收到 JSON 數(shù)據(jù),很輕松就可以轉(zhuǎn)換為 Python 對象(例如字典)并使用它。這對于概念驗證代碼或很小的 JSON 字符串來說是很好的選擇。如果你不將其轉(zhuǎn)換為 dataclass 之類的,它將一團糟。
pydantic 是一個超級有用的驗證庫。你可以使用自己喜歡的 JSON 庫將 JSON 字符串解析為帶有 字典/列表/字符串/數(shù)字/布爾值的 Python 基本表示形式,然后再使用 Pydantic 對其進行解析。這樣做的好處是你知道以后要處理的內(nèi)容。不再只是將 Dict[str, Any] 用作 type annotation,不再用沒用的的編輯器自動完成,不再檢查屬性是否在整個代碼中都存在。
要引入除默認(rèn) json 以外的其他 json 包,我建議使用此模式
import ujson as json
對于 Flask,你可以使用其他 編碼器/解碼器,如下所示:
from simplejson import JSONEncoder, JSONDecoder
app.json_encoder = JSONEncoder
app.json_decoder = JSONDecoder

近期熱門文章推薦:

