在我的应用中,序列化就是把类转成符合JSON格式的字符串,反序列化就是把JSON格式的字符串转换成类。C#的话直接用Newtonsoft.JSON就可以了,非常好用。本来以为python也会有类似的库,但是貌似并没有。网上查了一些python用来实现JSON序列化和反序列化的方法,用的最多的就是json.loads, json.dumps。
# 序列化:将Python对象转换成json字符串 dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False, **kw) # 反序列化:将json字符串转换成Python对象 loads(s, encoding=None, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw)
# 序列化:将Python对象转换成json字符串并存储到文件中 dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, cls=None, indent=None, separators=None, default=None, sort_keys=False, **kw) # 反序列化:读取指定文件中的json字符串并转换成Python对象 load(fp, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, object_pairs_hook=None, **kw)
包含自定义类的序列化例子:
from typing import List class Address: def __init__(self,country,city): self.country=country self.city=city class Student: def __init__(self,name,age,sex,address): self.name=name self.age=age self.sex=sex self.address=address class School: def __init__(self,name,address:Address,students:List[Student]): self.name=name self.address=address self.students=students import json addr1=Address('China','Beijing') stu1=Student('lily',20,'female',Address('China','Shanghai')) stu2=Student('tom',23,'male',Address('China','Shenzhen')) sch1=School('MathSchool',addr1,[stu1,stu2]) # 先把python对象转换为dict对象,进而才能实现序列化 json_data=json.dumps(sch1,default=lambda o:o.__dict__,indent=2) print(json_data)
输出结果为:

{ "name": "MathSchool", "address": { "country": "China", "city": "Beijing" }, "students": [ { "name": "lily", "age": 20, "sex": "female", "address": { "country": "China", "city": "Shanghai" } }, { "name": "tom", "age": 23, "sex": "male", "address": { "country": "China", "city": "Shenzhen" } } ] }
再把生成的json_data反序列化
sch2=School(**json.loads(json_data)) print(type(sch2)) print(type(sch2.students)) print(type(sch2.address))
输出的结果为:
<class '__main__.School'> <class 'list'> <class 'dict'>
可见,这样的反序列化无法直接生成School类中的address属性和students属性。address的类型仍为dict,而students的类型是list。因此需要再把address的dict转换为Address,把students的list转换成List[Student]。
sch2=School(**json.loads(json_data)) sch2.address=Address(**json.loads(json.dumps(sch2.address))) students=[] for stu in sch2.students: students.append(Student(**json.loads(json.dumps(stu)))) sch2.students=students
也就是说,要这样才能生成一个完整的School类。总感觉太麻烦了,不像用newtonsoft.json那么方便。于是在网上搜到了Refs[2]这篇帖子,用了里面的方法,其实这个方法就是构造了一个创建类的Structure基类。这个方法对于List[Student]这种属性我依然不能很好的解决,总感觉就差了一点点,但是我python用的没有很熟练,也只能这样了。Structure基类的代码为:
class Structure(object): _fields=[] def __init_arg(self,expected_type,value): if isinstance(value,expected_type): return value else: return expected_type(**value) def __init__(self, **kwargs): field_names,field_types = zip(*self._fields) assert([isinstance(field_name,str) for field_name in field_names]) assert([isinstance(type_,type)for type_ in field_types]) for field_name,field_type in self._fields: setattr(self,field_name,self.__init_arg(field_type, kwargs.pop(field_name))) if kwargs: raise TypeError('Invalid arguments(s):{}'.format(','.join(kwargs)))
继承该类,那么School, Address, Student类分别为:
class Address(Structure): _fields=[('country',str),('city',str)] class Student(Structure): _fields=[('name',str),('age',int),('sex',str),('address',Address)] class School(Structure): _fields=[('name',str),('address',Address),('students',list)]
序列化和反序列化:其中序列化还是使用json,反序列化则没有使用json
import json addr=Address(**{'country':'China','city':'Beijing'}) stu1=Student(**{'name':'lily','age':18,'sex':'female','address':addr}) stu2=Student(**{'name':'tom','age':19,'sex':'male','address':addr}) sch=School(**{'name':'mathSchool','address':addr,'students':[stu1,stu2]}) # 序列化sch对象,生成字符串 json_data=json.dumps(sch,default=lambda o:o.__dict__,indent=2) # 将json_data字符串转换为dict data=json.loads(json_data) # 反序列化data,得到sch1对象 sch1=School(**data) # 反序列化可以直接获取到sch1.address对象,但是对于students对象还是不行 print(type(sch1.address)) # list类型的students属性还是要这样生成一下 students=[] for stu in sch1.students: students.append(Student(**stu)) sch1.students=students
Refs:
python:序列化与反序列化(json、pickle、shelve) - 秋寻草 - 博客园 (cnblogs.com)
Deserializing nested dictionaries into complex, typed(!) python objects (seanjohnsen.com)