前幾天有同事問如何將一個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效果