zoukankan      html  css  js  c++  java
  • Python实现JSON序列化和反序列化

    在我的应用中,序列化就是把类转成符合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)

  • 相关阅读:
    伙伴宿舍管理系统(源码下载)
    清空SQL数据库日志
    indexOf(String.indexOf 方法)
    C#实现QQ助手(登录QQ,发消息,查任意QQ资料)附源码下载
    C#cookie自动获取工具发布
    winform中怎么动态修改窗体的大小
    IIS Rewrite 下载与配置
    HTML代码转JS|C#字符串工具(附源代码)
    FTPHelper-FTP帮助类,常用操作方法
    c# 怎么动态修改webservice的地址和端口 动态修改配置文
  • 原文地址:https://www.cnblogs.com/larissa-0464/p/15214336.html
Copyright © 2011-2022 走看看