Python解析JSON爲實體

前幾天有同事問如何將一個json字符串反序列化爲實體,當時只是簡單找了一下方案,並未對這個事情做深入的瞭解。一致感覺這個挺有意思於是今晚就搜索了一些資料並作了測試,感興趣的同學可以進一步深入料及。總而,感覺python的就是可以寫很少代碼,引入一些現有包就可以輕易實現自己想要的功能。

單層實體:

自定義一個單層實體公共類JsonClass.py:

#!/usr/bin/python
import json

class JsonClass(object):
    def to_json_string(self):
        return json.dumps(self, default=lambda obj: obj.__dict__)

    def from_json_string(self, json_string):
        data = json.loads(json_string)
        for key in self.__dict__.keys():
            setattr(self, key, data[key])

根據自己的需要反序列化的json字符串定義實體:

{"timestamp": 1560948789.5293133, "name": "a", "id": 1}

自定義實體Task.py

from com.dx.test.JsonClass import JsonClass

class Task(JsonClass):
    def __init__(self, id=None, name=None, timestamp=None):
        self.id = id
        self.name = name
        self.timestamp = timestamp

測試類TaskTest.py

#!/usr/bin/python
import time
from com.dx.test.Task import Task

if __name__ == '__main__':
    # 序列化
    task = Task(1, "a", time.time())
    print(task.to_json_string())

    # 反序列化
    json_string = '{"timestamp": 1560948789.5293133, "name": "a", "id": 1}'
    task = Task()
    task.from_json_string(json_string)
    print(task.id)

Debug後截圖效果:

多層實體:

方案一(採用自定函數解析實體):

自定義json_deserialize函數實現多層解析:

import json

def json_deserialize(json_data, obj):
    py_data = json.loads(json_data)
    dic2class(py_data, obj)


'''
Dict convert to Class
通過setattr函數賦值屬性,如果有值就賦值屬性和值
'''
def dic2class(py_data, obj):
    for name in [name for name in dir(obj) if not name.startswith('_')]:
        if name not in py_data:
            setattr(obj, name, None)
        else:
            value = getattr(obj, name)
            setattr(obj, name, set_value(value, py_data[name]))



'''
設置虛擬類屬性值
'''
def set_value(value, py_data):
    if str(type(value)).__contains__('.'):
        # value 爲自定義類
        dic2class(py_data, value)
    elif str(type(value)) == "<class 'list'>":
        # value爲列表
        if value.__len__() == 0:
            # value列表中沒有元素,無法確認類型
            value = py_data
        else:
            # value列表中有元素,以第一個元素類型爲準
            child_value_type = type(value[0])
            value.clear()
            for child_py_data in py_data:
                child_value = child_value_type()
                child_value = set_value(child_value, child_py_data)
                value.append(child_value)
    else:
        value = py_data
    return value

根據自己json字符串自定義實體:

 

class Meta:
    currentPage = 0
    pageSize = 0
    realSize = 0
    startIndex = 0
    totalCount = 0
    totalPages = 0


class Data:
    centerCode = ""
    centerName = ""
    createTime = ""
    createUser = ""
    createUserId = ""
    districtCode = ""
    districtName = ""
    groupCode = ""
    groupName = ""
    id = 0
    latitude = ""
    longitude = ""
    plazaCode = ""
    plazaName = ""
    tenantId = ""
    updateTime = ""
    updateUser = ""
    updateUserId = ""
    version = 0


class Result:
    data = [Data()]
    message = ""
    meta = Meta()
    status = 0

解析實體測試類:

#!/usr/bin/python

import requests
import json
from com.dx.test.SelfDefParseJson import json_deserialize
from com.dx.test.Result import Result

url = "http://wdspinspector.intra.uat.beyonds.gw/phoenix/inspector/v1/baseinfos";
headers = {
    "tenantId": "xx",
}
params = {
    "p": 1,
    "ps": 20,
    "groupCode": "xx"
}
response = requests.get(url, params=params, headers=headers)
responseJsonFormat = json.dumps(response.json(), sort_keys=True, indent=4, separators=(',', ': '))

result = Result()
json_deserialize(responseJsonFormat, result)

Debug效果

方案二(安裝from addict import Dict,任何層json都可以反序列化):

這種方式比較簡單,只需要安裝addict包。

Installing

You can install via pip

pip install addict

or through conda

conda install addict -c conda-forge

Addict runs on Python 2 and Python 3, and every build is tested towards 2.7, 3.6 and 3.7.

測試代碼:

#!/usr/bin/python

import requests
import json
from com.dx.test.Result import Result
from addict import Dict

url = "http://xxx/xx/xx";
headers = {
    "tenantId": "xx",
}
params = {
    "p": 1,
    "ps": 20,
    "groupCode": "xx"
}
response = requests.get(url, params=params, headers=headers)

dict = Dict(response.json())
print(dict.data[0].plazaName)
print(dict.meta.totalCount)

Debug效果

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章