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