許多Python標準庫都有一些未被賞識的精華。其中之一是允許簡單優雅的基于參數類型的函數分發。這一特性對于任意對象的序列化而言是非常完美的——例如對于web API的JSON或結構化日志而言。
誰應該都見過這個:
雖然這不是什么大問題。json模塊(API繼承自simplejson)提供了兩種方式來序列化對象:
1. 實現一個default()函數,它接收一個對象作為參數并且返回可以被JSONEncoder理解的東西;
2. 你自己實現或子類化一個JSONEncoder,并且把它作為cls傳遞給dump方法。你可以自己實現它或者簡單地重寫JSONEncoder.default()方法。
由于一些第三方的實現希望能夠被大多數程序兼容,所以他們都不同程度的模仿了json模塊的API1。
擴展性
所有上述方法的共性是它們不具有擴展性:不提供對新類型的支持。你的default()函數需要知道所有你想要序列化的自定義類型。這意味著你或者像這樣寫你的函數:
這看起來非常痛苦,因為你需要在一個地方為所有不同類型對象增加序列化結果2。
或者另一種方法,你可以自己嘗試提出一種一般性的解決方案,就像Pyramid的JSON渲染器在JSON.add_adapter中做的一樣,它使用了被廣泛低估的zope.interface的適配器注冊表3。
另一方面,Django自己實現了一個DjangoJSONEncoder,它是json.JSONEncoder的子類,它知道如何去編碼日期,時間,UUID和premise等。但是除此之外,你又需要依靠自己了。如果你想深入研究Django和web API,那么你可能已經準備好使用Django的REST框架了。它們實現了一整套序列化系統,它比僅僅讓數據進行json.dump()做了更多的工作。
最后,為了完整性,我感覺我不得不提到我自己在我第一天開始就極其討厭的structlog中的解決方案:為你的類增加一個__structlog__方法,它會像__str__一樣返回一個序列化后的表示方法。請不要重復我的錯誤。標簽:software clown。
JSON已經很流行了,然而很奇怪的是我們對于序列化的解決方案卻仍舊不夠完善。我個人想要的是能夠注冊一個中心化的序列化工具,但是卻以一個去中心化的方式來使用,這樣可以不需要對我的類(或者更糟的,第三方類)進行任何修改。
進入PEP443
Python3.4以PEP 443的形式給出了對這個問題的一個好的解決方案:functools.singledispatch(老式Python版本也可以在PyPI上找到)。
簡單說,你可以定義一個默認的函數然后根據第一個參數的類型注冊一個該函數的額外版本:
現在你也可以對datetime實例調用to_serializable()方法,singledispatch會選擇正確的函數
這一方法讓你能夠把你的序列化器放在任何你想放的位置:放在類里,在一個獨立的模塊里,或者放在JSON相關的代碼里。你自己選!但是你的類要保持干凈,并且你不需要巨大的繁瑣的if-elif-else分支。
更深入一點
顯然,@singledispatch的使用比JSON更加深入。一般而言,為不同類型的對象綁定不同的行為以及獨立的序列化方式是普遍適用的4。我的一些校對員提到了他們嘗試了采用字典類近似替代可調用對象以及其他一些類似的“殘暴的”做法。
換句話說,@singledispatch就是一個長久以來就存在的但是卻被你忽略的函數。
P.S. 當然,PyPI中也有一個*multiple*dispatch。
腳注
1. 然而,對于非常出名的一個:UltraJSON一點都不支持自定義對象的序列化,此外,python-rapidjson僅僅支持default()函數。
2. 利用attrs是可以很好管理的!也許你應當使用attrs!
3. 不幸的是Pyramid使用的API自從zope.component移植過來之后還沒有形成文檔。
4. 我聽說將singlepatch加進標準庫的最原始動力來自于對pprint的一個更優雅的實現(雖然從來沒有實現過)
原文鏈接:https://hynek.me/articles/serialization/
(版權歸原作者所有,侵刪)
編輯:jq
-
API
+關注
關注
2文章
1502瀏覽量
62099 -
函數
+關注
關注
3文章
4333瀏覽量
62686 -
代碼
+關注
關注
30文章
4791瀏覽量
68685 -
python
+關注
關注
56文章
4797瀏覽量
84745 -
JSON
+關注
關注
0文章
119瀏覽量
6977
原文標題:更好的Python對象序列化方式
文章出處:【微信號:magedu-Linux,微信公眾號:馬哥Linux運維】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論