Python實(shí)現(xiàn)JSON反序列化類對(duì)象的示例
我們的網(wǎng)絡(luò)協(xié)議一般是把數(shù)據(jù)轉(zhuǎn)換成JSON之后再傳輸。之前在Java里面,實(shí)現(xiàn)序列化和反序列化,不管是 jackson ,還是 fastjson 都非常的簡(jiǎn)單?,F(xiàn)在有項(xiàng)目需要用Python來(lái)開發(fā),很自然的希望這樣的便利也能在Python中體現(xiàn)。
但是在網(wǎng)上看了一些教程,講反序列化的時(shí)候,基本都是轉(zhuǎn)換為 dict 或者 array 。這種編程方式我從情感上是無(wú)法接受的。難道是這些JSON庫(kù)都不支持反序列化為類對(duì)象?我馬上打消了這個(gè)念頭,Python這樣強(qiáng)大的腳本語(yǔ)言,不可能沒(méi)有完善的JSON庫(kù)。
于是我就研究了一下原生的 json ,以及第三方的 demjson 和 simplejson 。
一、原生json
我仔細(xì)研究了原生 json 的 loads 方法的定義
def loads(s, encoding=None, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw)
這里面的 object_hook 和 object_pairs_hook 參數(shù)引起了我的注意,我重點(diǎn)說(shuō)一下 object_hook 。
官方文檔的說(shuō)明如下:
object_hook is an optional function that will be called with the result of any object literal decoded (a dict). The return value of object_hook will be used instead of the dict. This feature can be used to implement custom decoders (e.g. JSON-RPC class hinting).
這個(gè) object_hook 根據(jù)文檔的解釋就是一個(gè)自定義解碼函數(shù),入?yún)?shù)標(biāo)準(zhǔn)反序列化后的dict,我們可以根據(jù)自己的規(guī)則轉(zhuǎn)換輸出為想要的格式。
我又去搜了一下 object_hook ,大家對(duì)于這個(gè)東西的處理方式基本就是用一個(gè)靜態(tài)方法把dict轉(zhuǎn)換成對(duì)象。
我們的數(shù)據(jù)結(jié)構(gòu)是這樣的
{"status":1,"info":"發(fā)布成功","data":{"id":"52","feed_id":"70"}}
于是我就寫了這樣的代碼:
class Response:
def __init__(self, status, info, data) -> None:
super().__init__()
self.status = status
self.info = info
self.data = data
@staticmethod
def object_hook(d):
return Response(d['status'], d['info'], d['data'])
...
resp = json.loads(body, object_hook=Response.object_hook)
一開始呢,確實(shí)沒(méi)有問(wèn)題,雖然用起來(lái)沒(méi)有java的json庫(kù)辣么方便,但總歸實(shí)現(xiàn)了需求。
好景不長(zhǎng),我測(cè)試的第一個(gè)接口返回的數(shù)據(jù)中, data 是字段一個(gè)字符串,反序列化正常??墒呛髞?lái)當(dāng)接口返回的結(jié)構(gòu)中 data 字段是一個(gè)dict結(jié)構(gòu)的時(shí)候, object_hook 的入?yún)⒕尤蛔兂闪?data 字段轉(zhuǎn)換之后的dict( {"id":"52","feed_id":"70"} ),而不是完整的數(shù)據(jù)。
這些懵逼了,上網(wǎng)搜索了一圈沒(méi)有結(jié)論。于是上網(wǎng)搜了一圈,也沒(méi)有結(jié)論。 好吧,我最后又回到官方文檔, read the fucking official document 。
不看不知道,一看嚇一跳,官方文檔用了一種巧妙的方式實(shí)現(xiàn)了上面的需求。
>>> class JSONObject: ... def __init__(self, d): ... self.__dict__ = d ... >>> >>> data = json.loads(s, object_hook=JSONObject) >>> data.name 'ACME' >>> data.shares 50 >>> data.price 490.1 >>>
我服了,把json解析之后的dict直接賦值給對(duì)象的屬性dict,然后就可以隨心所欲的使用屬性了,真心方便,動(dòng)態(tài)語(yǔ)言就是好。
以上是官方的json庫(kù)實(shí)現(xiàn)方案,那另外兩個(gè)知名的第三方庫(kù)呢?
二、demjson
demjson 也支持 hook 。有兩種配置的方式: decode 函數(shù)配置和 set_hook 函數(shù)配置
1. decode
def decode( txt, encoding=None, **kwargs )
decode 函數(shù)可以指定很多參數(shù),其中就包括 hook 函數(shù)。 hook 函數(shù)的指定是使用鍵值對(duì)的方式,鍵是 hook 函數(shù)的名稱,值是 hook 函數(shù)。
demjson是通過(guò)名字來(lái)管理hook函數(shù)的,所以hookname不是隨便指定的,必須是內(nèi)置的幾種hook函數(shù)的名稱。
- decode_number
- decode_float
- decode_object
- decode_array
- decode_string
- encode_value
- encode_dict
- encode_dict_key
- encode_sequence
- encode_bytes
- encode_default
demjson.decode(body, encode='utf-8',decode_obbject=Reponse.object_hook)
結(jié)果并沒(méi)有讓我很開森,依然是無(wú)法處理嵌套結(jié)構(gòu)。 日志中顯示如下內(nèi)容:
2018-01-30 16:01:17,137 poster.py post_all 73 INFO : {"status":1,"info":"\u53d1\u5e03\u6210\u529f","data":{"id":"54","feed_id":"72"}}
2018-01-30 16:01:17,138 response.py object_hook 13 INFO : {'id': '54', 'feed_id': '72'}
2018-01-30 16:01:17,138 response.py object_hook 13 INFO : {'status': 1, 'info': '發(fā)布成功', 'data': demjson.undefined}
很奇怪的是 object_hook 函數(shù)被調(diào)用了兩次,第一次是 data 字段的內(nèi)容,第二是全部的內(nèi)容,但是 data 字段沒(méi)有解析出來(lái)。 非常奇怪,百思不得其解!??!
2. set_hook
set_hook 函數(shù)跟上面的 decode 函數(shù)不一樣,它是 JSON 類的成員函數(shù),而 decode 函數(shù)是個(gè)靜態(tài)函數(shù)。
def set_hook(self, hookname, function)
吸取之前的教訓(xùn),這次我仔細(xì)閱讀了demjson的文檔,還真發(fā)現(xiàn)點(diǎn)東西。
Netsted values. When decoding JSON that has nested objects or arrays, the decoding hooks will be called once for every corresponding value, even if nested. Generally the decoding hooks will be called from the inner-most value outward, and then left to right.
這里重點(diǎn)說(shuō)到嵌套的問(wèn)題,出現(xiàn)嵌套的時(shí)候,每個(gè)對(duì)應(yīng)的類型都會(huì)調(diào)用 hook 函數(shù)一次,而且是從最內(nèi)層,從左往右。好吧,之前出現(xiàn)的問(wèn)題全部明白了,原來(lái)都是這個(gè)規(guī)則惹的禍,但是為什么這樣設(shè)計(jì)我暫時(shí)還是不明白。
set_hook 的使用方式
j = demjson.JSON() j.set_hook( 'decode_array', my_sort_array ) j.decode(body, encode='utf-8')
三、simplejson
前面說(shuō)了那么多, simplejson 的方式就沒(méi)什么可說(shuō)的,跟官方的 json 庫(kù) hook 方式一致。
總結(jié)
雖然我的需求是滿足了,但是還是有一個(gè)大大的問(wèn)號(hào)留在我心中,為什么是這樣設(shè)計(jì),網(wǎng)上沒(méi)有找到合適的答案,剩下的需要研究源代碼分析了。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Python如何把不同類型數(shù)據(jù)的json序列化
- Python爬蟲數(shù)據(jù)的分類及json數(shù)據(jù)使用小結(jié)
- Python xml、字典、json、類四種數(shù)據(jù)類型如何實(shí)現(xiàn)互相轉(zhuǎn)換
- Python 之 Json序列化嵌套類方式
- python聚類算法解決方案(rest接口/mpp數(shù)據(jù)庫(kù)/json數(shù)據(jù)/下載圖片及數(shù)據(jù))
- 詳解Python對(duì)JSON中的特殊類型進(jìn)行Encoder
- 把JSON數(shù)據(jù)格式轉(zhuǎn)換為Python的類對(duì)象方法詳解(兩種方法)
- 在Python?中將類對(duì)象序列化為JSON
相關(guān)文章
對(duì)pytorch的函數(shù)中的group參數(shù)的作用介紹
今天小編就為大家分享一篇對(duì)pytorch的函數(shù)中的group參數(shù)的作用介紹,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-02-02
Python如何使用WebSocket實(shí)現(xiàn)實(shí)時(shí)Web應(yīng)用
這篇文章主要介紹了Python使用WebSocket實(shí)現(xiàn)實(shí)時(shí)Web應(yīng)用,Django?Channels?提供了強(qiáng)大的功能,使得在?Django?中實(shí)現(xiàn)實(shí)時(shí)功能變得更加容易,你可以在此基礎(chǔ)上擴(kuò)展,添加更多功能和復(fù)雜的邏輯,需要的朋友可以參考下2024-08-08
pandas中的ExcelWriter和ExcelFile的實(shí)現(xiàn)方法
這篇文章主要介紹了pandas中的ExcelWriter和ExcelFile的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04
opencv python 基于KNN的手寫體識(shí)別的實(shí)例
這篇文章主要介紹了opencv python 基于KNN的手寫體識(shí)別的實(shí)例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-08-08
Pandas merge合并兩個(gè)DataFram的實(shí)現(xiàn)
本文主要介紹了Pandas merge合并兩個(gè)DataFram的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-03-03
python 基于pygame實(shí)現(xiàn)俄羅斯方塊
這篇文章主要介紹了python 基于pygame實(shí)現(xiàn)俄羅斯方塊的方法,幫助大家更好的理解和學(xué)習(xí)使用python,感興趣的朋友可以了解下2021-03-03
Django定時(shí)任務(wù)Django-crontab的使用詳解
測(cè)試平臺(tái)執(zhí)行測(cè)試用例時(shí),可以借助jenkins之類的CI/CD工具,也可以使用定時(shí)任務(wù)crontab,作為測(cè)試開發(fā)工程師,我們可能沒(méi)有權(quán)限去操作服務(wù)器,那么我們就只能使用django-crontab,在指定時(shí)間循環(huán)執(zhí)行測(cè)試用例,對(duì)定時(shí)任務(wù)Django-crontab的使用感興趣的朋友一起看看吧2022-07-07

