久久福利_99r_国产日韩在线视频_直接看av的网站_中文欧美日韩_久久一

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

利用Python實(shí)現(xiàn)Json序列化庫(kù)的方法步驟

瀏覽:5日期:2022-07-11 18:16:26

前言

在Python的世界里,將一個(gè)對(duì)象以json格式進(jìn)行序列化或反序列化一直是一個(gè)問(wèn)題。Python標(biāo)準(zhǔn)庫(kù)里面提供了json序列化的工具,我們可以簡(jiǎn)單的用json.dumps來(lái)將一個(gè)對(duì)象序列化。但是這種序列化僅支持python內(nèi)置的基本類(lèi)型。

利用Python實(shí)現(xiàn)Json序列化庫(kù)的方法步驟Python

在Python的世界里,將一個(gè)對(duì)象以json格式進(jìn)行序列化或反序列化一直是一個(gè)問(wèn)題。Python標(biāo)準(zhǔn)庫(kù)里面提供了json序列化的工具,我們可以簡(jiǎn)單的用json.dumps來(lái)將一個(gè)對(duì)象序列化。但是這種序列化僅支持python內(nèi)置的基本類(lèi)型,對(duì)于自定義的類(lèi),我們將得到Object of type A is not JSON serializable的錯(cuò)誤。

有很多種方法可以用來(lái)支持這種序列化,這里有一個(gè)很長(zhǎng)的關(guān)于這個(gè)問(wèn)題的討論。總結(jié)起來(lái),基本上有兩種還不錯(cuò)的思路:

利用標(biāo)準(zhǔn)庫(kù)的接口:從python標(biāo)準(zhǔn)json庫(kù)中的JSONDecoder繼承,然后自定義實(shí)現(xiàn)一個(gè)default方法用來(lái)自定義序列化過(guò)程 利用第三方庫(kù)實(shí)現(xiàn):如jsonpickle jsonweb json-tricks等

利用標(biāo)準(zhǔn)庫(kù)的接口的問(wèn)題在于,我們需要對(duì)每一個(gè)自定義類(lèi)都實(shí)現(xiàn)一個(gè)JSONDecoder.default接口,難以實(shí)現(xiàn)代碼復(fù)用。

利用第三方庫(kù),對(duì)我們的代碼倒是沒(méi)有任何侵入性,特別是jsonpickle,由于它是基于pickle標(biāo)準(zhǔn)序列化庫(kù)實(shí)現(xiàn),可以實(shí)現(xiàn)像pickle一樣序列化任何對(duì)象,一行代碼都不需要修改。

但是我們觀(guān)察這類(lèi)第三方庫(kù)的輸出的時(shí)候,會(huì)發(fā)現(xiàn)所有的這些類(lèi)庫(kù)都會(huì)在輸出的json中增加一個(gè)特殊的標(biāo)明對(duì)象類(lèi)型的屬性。這是為什么呢?Python是一門(mén)動(dòng)態(tài)類(lèi)型的語(yǔ)言,我們無(wú)法在對(duì)象還沒(méi)有開(kāi)始構(gòu)建的時(shí)候知道對(duì)象的某一屬性的類(lèi)型信息,為了對(duì)反序列化提供支持,看起來(lái)確實(shí)是不得不這么做。

有人可能覺(jué)得這也無(wú)可厚非,似乎不影響使用。但是在跨語(yǔ)言通信的時(shí)候,這就成為了一個(gè)比較麻煩的問(wèn)題。比如我們有一個(gè)Python實(shí)現(xiàn)的API,客戶(hù)端發(fā)送了一個(gè)json請(qǐng)求過(guò)來(lái),我們想在統(tǒng)一的一個(gè)地方將json反序列化為我們Python代碼的對(duì)象。由于客戶(hù)端不知道服務(wù)器端的類(lèi)型信息,json請(qǐng)求里面就沒(méi)法加入這樣的類(lèi)型信息,這也就導(dǎo)致這樣的類(lèi)庫(kù)在反序列化的時(shí)候遇到問(wèn)題。

能不能有一個(gè)相對(duì)完美的實(shí)現(xiàn)呢?先看一下我們理想的json序列化庫(kù)的需求:

我們希望能簡(jiǎn)單的序列化任意自定義對(duì)象,只添加一行代碼,或者不加入任何代碼 我們希望序列化的結(jié)果不加入任何非預(yù)期的屬性 我們希望能按照指定的類(lèi)型進(jìn)行反序列化,能自動(dòng)處理嵌套的自定義類(lèi),只需要自定義類(lèi)提供非常簡(jiǎn)單的支持,或者不需要提供任何支持 我們希望反序列化的時(shí)候能很好的處理屬性不存在的情況,以便在我們加入某一屬性的時(shí)候,可以設(shè)置默認(rèn)值,使得舊版本的序列化結(jié)果可以正確的反序列化出來(lái)

如果有一個(gè)json庫(kù)能支持上面的四點(diǎn),那就基本是比較好用的庫(kù)了。下面我們來(lái)嘗試實(shí)現(xiàn)一下這個(gè)類(lèi)庫(kù)。

對(duì)于我們想要實(shí)現(xiàn)的幾個(gè)需求,我們可以建立下面這樣的測(cè)試來(lái)表達(dá)我們所期望的庫(kù)的API設(shè)計(jì):

class A(JsonSerializable):def __init__(self, a, b):super().__init__()self.a = aself.b = b if b is not None else B(0)@propertydef id(self):return self.adef _deserialize_prop(self, name, deserialized):if name == ’b’:self.b = B.deserialize(deserialized)returnsuper()._deserialize_prop(name, deserialized)class B(JsonSerializable):def __init__(self, b):super().__init__()self.b = bclass JsonSerializableTest(unittest.TestCase):def test_model_should_serialize_correctly(self):self.assertEqual(json.dumps({’a’: 1, ’b’: {’b’: 2}}), A(1, B(2)).serialize())def test_model_should_deserialize_correctly(self):a = A.deserialize(json.dumps({’a’: 1, ’b’: {’b’: 2}}))self.assertEqual(1, a.a)self.assertEqual(2, a.b.b)def test_model_should_deserialize_with_default_value_correctly(self):a = A.deserialize(json.dumps({’a’: 1}))self.assertEqual(1, a.a)self.assertEqual(0, a.b.b)

這里我們希望通過(guò)繼承的方式來(lái)添加支持,這將在反序列化的時(shí)候提供一個(gè)好處。因?yàn)橛辛怂覀兙涂梢灾苯邮褂肁.deserialize方法來(lái)反序列化,而不需要提供任何其他的反序列化函數(shù)參數(shù),比如這樣json.deserialize(serialized_str, A)。

同時(shí)為了驗(yàn)證我們的框架不會(huì)將@property屬性序列化或者反序列化,我們特意在類(lèi)A中添加了這樣一個(gè)屬性。

由于在反序列化的時(shí)候,框架是無(wú)法知道某一個(gè)對(duì)象屬性的類(lèi)型信息,比如測(cè)試中的A.b,為了能正確的反序列化,我們需要提供一點(diǎn)簡(jiǎn)單的支持,這里我們?cè)陬?lèi)A中覆蓋實(shí)現(xiàn)了一個(gè)父類(lèi)的方法_deserialize_prop對(duì)屬性b的反序列化提供支持。

當(dāng)我們要反序列化一個(gè)之前版本的序列化結(jié)果時(shí),我們希望能正確的反序列化并使用我們提供的默認(rèn)值作為最終的反序列化值。這在屬性A.b的測(cè)試中得到了體現(xiàn)。

(上面的測(cè)試有很多邊界的情況、支持的變量類(lèi)型并沒(méi)有覆蓋,此測(cè)試只是作為示例使用。)

如果能有一個(gè)類(lèi)可以讓上面的測(cè)試通過(guò),相信那個(gè)類(lèi)就是我們所需要的類(lèi)了。這樣的類(lèi)可以實(shí)現(xiàn)為如下:

def is_normal_prop(obj, key):is_prop = isinstance(getattr(type(obj), key, None), property)is_func_attr = callable(getattr(obj, key))is_private_attr = key.startswith(’__’)return not (is_func_attr or is_prop or is_private_attr)def is_basic_type(value):return value is None or type(value) in [int, float, str, bool]class JsonSerializable:def _serialize_prop(self, name):return getattr(self, name)def _as_dict(self):props = {}for key in dir(self):if not is_normal_prop(self, key):continuevalue = self._serialize_prop(key)if not (is_basic_type(value) or isinstance(value, JsonSerializable)):raise Exception(’unknown value to serialize to dict: key={}, value={}’.format(key, value))props[key] = value if is_basic_type(value) else value._as_dict()return propsdef serialize(self):return json.dumps(self._as_dict(), ensure_ascii=False)def _deserialize_prop(self, name, deserialized):setattr(self, name, deserialized)@classmethoddef deserialize(cls, json_encoded):if json_encoded is None:return Noneargs = inspect.getfullargspec(cls)args_without_self = args.args[1:]obj = cls(*([None] * len(args_without_self)))data = json.loads(json_encoded, encoding=’utf8’) if type(json_encoded) is str else json_encodedfor key in dir(obj):if not is_normal_prop(obj, key):continueif key in data:obj._deserialize_prop(key, data[key])return obj

在實(shí)現(xiàn)時(shí),我們利用了Python的內(nèi)省機(jī)制,這樣就可以自動(dòng)的識(shí)別對(duì)象的屬性及運(yùn)行時(shí)類(lèi)型了。當(dāng)然對(duì)于這個(gè)簡(jiǎn)單的類(lèi)還有很多待支持的功能,使用上也有很多限制,比如:

當(dāng)某一屬性為自定義類(lèi)的類(lèi)型的時(shí)候,需要子類(lèi)覆蓋實(shí)現(xiàn)_deserialize_prop方法為反序列化過(guò)程提供支持 當(dāng)某一屬性為由自定義類(lèi)構(gòu)成的一個(gè)list tuple dict復(fù)雜對(duì)象時(shí),需要子類(lèi)覆蓋實(shí)現(xiàn)_deserialize_prop方法為反序列化過(guò)程提供支持 簡(jiǎn)單屬性必須為python內(nèi)置的基礎(chǔ)類(lèi)型,比如如果某一屬性的類(lèi)型為numpy.float64,序列化反序列化將不能正常工作

雖然有上述限制,但是這正好要求我們?cè)谧瞿P驮O(shè)計(jì)的時(shí)候保持克制,不要將某一個(gè)對(duì)象設(shè)計(jì)得過(guò)于復(fù)雜。比如如果有屬性為dict類(lèi)型,我們可以將這個(gè)dict抽象為另一個(gè)自定義類(lèi)型,然后用類(lèi)型嵌套的方式來(lái)實(shí)現(xiàn)。

到這里這個(gè)基類(lèi)就差不多可以支撐我們?nèi)粘5拈_(kāi)發(fā)需要了。當(dāng)然對(duì)于這個(gè)簡(jiǎn)單的實(shí)現(xiàn)還有可能有其他的需求或者問(wèn)題,大家如有發(fā)現(xiàn),歡迎留言交流。

總結(jié)

到此這篇關(guān)于利用Python實(shí)現(xiàn)Json序列化庫(kù)的文章就介紹到這了,更多相關(guān)Python實(shí)現(xiàn)Json序列化庫(kù)內(nèi)容請(qǐng)搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!

標(biāo)簽: Python 編程
相關(guān)文章:
主站蜘蛛池模板: 一区二区三区久久 | 国产日韩欧美精品 | 中文字幕成人影院 | 看全黄大色黄大片老人做 | av女人的天堂| 男女羞羞网站 | av在线一区二区三区 | 久久久久久网站 | 欧美一级片在线观看 | 天天天干天天天操 | 国产精品a一区二区三区网址 | 久久成人一区二区 | 久久99精品久久久久久久青青日本 | 欧美精品亚洲 | 亚洲在线视频 | 午夜在线电影 | 亚洲精品一区二区在线 | 中国91视频 | 国产成人一区二区三区 | aaa级片 | 国产aⅴ一区二区 | 久草在线在线精品观看 | 国产精品久久久久久久竹霞 | 亚洲精品乱码久久久久久蜜桃图片 | 国产日产精品一区二区三区四区 | 91综合网| 欧美久久免费 | 黄色大片成人 | 精品国产色 | 91免费看 | a√免费视频 | 亚洲综合无码一区二区 | 黄色a视频 | 四虎永久在线观看 | 性大毛片视频 | 狠狠躁夜夜躁人人爽天天高潮 | 日日摸天天做天天添天天欢 | 久久亚洲精品综合 | 国产在线高清视频 | 亚洲 欧美 另类 综合 偷拍 | 国产在亚洲 线视频播放 |