亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

 更新時(shí)間:2020年09月09日 09:09:22   作者:廖光明  
這篇文章主要給大家介紹了關(guān)于利用Python實(shí)現(xiàn)Json序列化庫的方法步驟,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

前言

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


Python

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

有很多種方法可以用來支持這種序列化,這里有一個(gè)很長的關(guān)于這個(gè)問題的討論??偨Y(jié)起來,基本上有兩種還不錯(cuò)的思路:

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

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

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

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

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

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

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

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

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

class A(JsonSerializable):

def __init__(self, a, b):
super().__init__()
self.a = a
self.b = b if b is not None else B(0)

@property
def id(self):
return self.a

def _deserialize_prop(self, name, deserialized):
if name == 'b':
self.b = B.deserialize(deserialized)
return
super()._deserialize_prop(name, deserialized)

class B(JsonSerializable):

def __init__(self, b):
super().__init__()
self.b = b

class 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)

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

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

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

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

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

如果能有一個(gè)類可以讓上面的測試通過,相信那個(gè)類就是我們所需要的類了。這樣的類可以實(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):
continue
value = 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 props

def serialize(self):
return json.dumps(self._as_dict(), ensure_ascii=False)

def _deserialize_prop(self, name, deserialized):
setattr(self, name, deserialized)

@classmethod
def deserialize(cls, json_encoded):
if json_encoded is None:
return None

args = 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_encoded
for key in dir(obj):
if not is_normal_prop(obj, key):
continue
if key in data:
obj._deserialize_prop(key, data[key])
return obj

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

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

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

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

總結(jié)

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

相關(guān)文章

  • Python實(shí)現(xiàn)極限車神游戲的示例代碼

    Python實(shí)現(xiàn)極限車神游戲的示例代碼

    今天小編要為大家介紹一款小編自己用Python代碼碼出來的賽車風(fēng)格的打字小游戲,不僅能游戲還能學(xué)到很多不同類型的編程代碼關(guān)鍵字的語言,需要的可以參考一下
    2023-02-02
  • Python上下文管理器全實(shí)例詳解

    Python上下文管理器全實(shí)例詳解

    在本篇文章里小編給大家整理的是關(guān)于Python上下文管理器全實(shí)例解析的知識點(diǎn),需要的朋友們參考下。
    2019-11-11
  • Python中的取模運(yùn)算方法

    Python中的取模運(yùn)算方法

    今天小編就為大家分享一篇Python中的取模運(yùn)算方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-11-11
  • 使用C語言來擴(kuò)展Python程序和Zope服務(wù)器的教程

    使用C語言來擴(kuò)展Python程序和Zope服務(wù)器的教程

    這篇文章主要介紹了使用C語言來擴(kuò)展Python程序和Zope服務(wù)器的教程,本文來自于IBM官方網(wǎng)站技術(shù)文檔,需要的朋友可以參考下
    2015-04-04
  • python實(shí)現(xiàn)二分查找算法

    python實(shí)現(xiàn)二分查找算法

    這篇文章主要介紹了python如何實(shí)現(xiàn)二分查找算法,幫助大家更好的理解和使用python,感興趣的朋友可以了解下。
    2020-09-09
  • 解決Mac下使用python的坑

    解決Mac下使用python的坑

    今天小編就為大家分享一篇解決Mac下使用python的坑,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-08-08
  • python繪制封閉多邊形教程

    python繪制封閉多邊形教程

    今天小編就為大家分享一篇python繪制封閉多邊形教程,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-02-02
  • python使用IPython調(diào)試debug程序

    python使用IPython調(diào)試debug程序

    這篇文章主要為大家介紹了python使用IPython調(diào)試debug程序詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-05-05
  • python中計(jì)算一個(gè)列表中連續(xù)相同的元素個(gè)數(shù)方法

    python中計(jì)算一個(gè)列表中連續(xù)相同的元素個(gè)數(shù)方法

    今天小編就為大家分享一篇python中計(jì)算一個(gè)列表中連續(xù)相同的元素個(gè)數(shù)方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-06-06
  • Python的這些庫,你知道多少?

    Python的這些庫,你知道多少?

    最近整理了一些好用的庫但是只是初級介紹,如果大家用得到的話還請自己到官網(wǎng)上查一下,因?yàn)闁|西太多我一 一介紹的話可能不太現(xiàn)實(shí),需要的朋友可以參考下
    2021-06-06

最新評論