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效果

 

posted @ 2020-11-16 21:55  cctext  阅读(1355)  评论(0编辑  收藏  举报