• Python-使用pickle和json进行序列化和反序列化


    原文地址:https://www.cnblogs.com/-beyond/p/15376680.html
    转载请先获得许可!!!

    python序列化与反序列化介绍

    序列化和反序列化,就是数据的格式转换,是相对的,一般是这样定义的:

    1. 将数据由X格式转换为Y格式,叫做序列化
    2. 将数据由Y格式转换为X格式,叫做反序列化

    常用的格式,比如xml、json、yaml、二进制;

    常用的序列化方式,比如json、二进制、hassian、protobuf、thrift....

    Python内置了一种数据序列化和反序列化的方式,也就是使用pickle模块,这个pickle模块将数据序列化后的内容,对于人来说是无法阅读的,但是使用pickle的反序列化,是能够将其解析为原始数据的,另外,picklepython的,其他编程语言无法处理pickle序列化后的数据,所以通用性不高。

    另外常用的JSON格式,python提供json模块来实现json的序列化与反序列化。

    python默认的序列化与反序列化

    python默认的序列化和反序列化,是指使用pickle模块,该模块是python自带的

    pickle序列化

    pickle序列化,使用的dumps()接口,直接传入需要序列化的数据即可,无论是啥类型都可以

    import pickle
    
    ######################## 序列化基本类型 #################
    a = "hello world"
    serialized_data = pickle.dumps(a)
    print(serialized_data)
    
    arr = [1, 2, 3, 4, 5, 6, 7, 8]
    serialized_data = pickle.dumps(arr)
    print(serialized_data)
    
    dt = {"abc": "123", "xyz": 456, 789: "999"}
    serialized_data = pickle.dumps(dt)
    print(serialized_data)
    
    ###################### 序列化自定义类型的数据 ##########
    
    class Person:
        level = "high"
    
        def __init__(self, name, age):
            self.__name = name
            self.__age = age
    
        def __str__(self):
            return "Person={__name:%s, __age:%s}" % (self.__name, self.__age)
    
        __repr__ = __str__
    
    
    p = Person("abc", 99)
    serialized_data = pickle.dumps(p)
    print(serialized_data)
    

    由于序列化后的内容不太好理解,就没有粘贴运行结果

    pickle反序列化

    反序列化,也就是将前面序列化后的数据,再转换为原始数据,也就是A -> B -> A中,B -> A的过程。

    pickle反序列化,使用的loads()接口

    import pickle
    
    ######################## 反序列化基本类型 #################
    
    a = "hello world"
    serialized_data = pickle.dumps(a)
    # 反序列化
    deserialized_data = pickle.loads(serialized_data)
    print(deserialized_data)
    # hello world
    
    arr = [1, 2, 3, 4, 5, 6, 7, 8]
    serialized_data = pickle.dumps(arr)
    # 反序列化
    deserialized_data = pickle.loads(serialized_data)
    print(deserialized_data)
    # [1, 2, 3, 4, 5, 6, 7, 8]
    
    dt = {"abc": "123", "xyz": 456, 789: "999"}
    serialized_data = pickle.dumps(dt)
    # 反序列化
    deserialized_data = pickle.loads(serialized_data)
    print(deserialized_data)
    # {'xyz': 456, 'abc': '123', 789: '999'}
    # 注意顺序变了
    
    ###################### 反序列化自定义类型的数据 ##########
    
    class Person:
        level = "high"
    
        def __init__(self, name, age):
            self.__name = name
            self.__age = age
    
        def __str__(self):
            return "Person={__name:%s, __age:%s}" % (self.__name, self.__age)
    
        __repr__ = __str__
    
    
    p = Person("abc", 99)
    serialized_data = pickle.dumps(p)
    deserialized_data = pickle.loads(serialized_data)
    print(deserialized_data)
    # Person={__name:abc, __age:99}
    

    序列化到文件以及将文件内容反序列化

    前面使用pickle.dumps()pickle.loads(),都是将内存中的数据,序列化后保存在内存中;如果要将序列化之后的数据保存到文件中,pickle提供了dump()接口和load()接口,也就是前面俩接口去掉后面的s即可。

    序列化后的内容写入文件,使用示例如下:

    import pickle
    
    fd = None
    try:
        # 打开要写入的文件
        fd = open("dt.txt", "wb")
    
        # 要写入的原始数据
        dt = {"abc": "123", "xyz": 456, 789: "999"}
    
        # 将数据序列化,并将结果写入文件中
        res = pickle.dump(dt, fd)
    
        print(res)  # None,没有返回值
    finally:
        if fd:
            fd.close()
    

    从文件反序列化的示例如下:

    import pickle
    
    fd = None
    try:
        # 打开要读取的文件
        fd = open("dt.txt", "rb")
    
        # 将数据序列化,并将结果写入文件中
        res = pickle.load(fd)
    
        print(res)  
        # {'xyz': 456, 'abc': '123', 789: '999'}
    finally:
        if fd:
            fd.close()
    

    注意,从文件中读取内容来反序列化,最好先确定文件内容大小,避免数据内容过大,导致内存不足。

    json序列化与反序列化

    python提供了json模块来支持json的序列化与反序列化操作,接口和pickle一样:

    1. dumps(),将数据序列化后存到内存里面;dump()则是将数据序列化后保存到文件中;
    2. loads(),将数据从内存中读取数据并反序列化;load()是从文件中读取数据并反序列化;

    Json序列化基本类型

    import json
    
    s = "hello world"
    serialized_data = json.dumps(s)
    print(serialized_data)
    # "hello world"
    
    arr = [1, 2, 3, 4, 5, 6]
    serialized_data = json.dumps(arr)
    print(serialized_data)
    # [1, 2, 3, 4, 5, 6]
    
    dt = {'xyz': 456, 'abc': '123', 789: '999'}
    serialized_data = json.dumps(dt)
    print(serialized_data)
    # {"xyz": 456, "abc": "123", "789": "999"}
    

    Json序列化自定义类型

    class Person:
        level = "high"
    
        def __init__(self, name, age):
            self.__name = name
            self.__age = age
    
        def __str__(self):
            return "Person={__name:%s, __age:%s}" % (self.__name, self.__age)
    
        __repr__ = __str__
    
    
    p = Person("abc", 99)
    serialized_data = json.dumps(p)
    print(serialized_data)
    # 出错了,raise TypeError(repr(o) + " is not JSON serializable")
    # TypeError: Person={__name:abc, __age:99} is not JSON serializable
    

    为什么使用pickle来序列化自定义类型的对象就不会有问题,而JSON序列化就会出现问题呢?

    这是因为json模块,在序列化自定义的类型时,它不知道应该怎么序列化这个对象,这个时候就需要我们为自定义的类型指定序列化的操作,比如序列化时:是否需要过滤某些字段、字段名叫什么、字段名是否做排序、字段值取什么值、值是否做格式转换....

    最简单的是使用lambda obj: obj.__dict__,也就是将对象当成dict,属性名就是key,属性值就是value,示例如下:

    class Person:
        level = "high"
    
        def __init__(self, name, age):
            self.__name = name
            self.__age = age
    
        def __str__(self):
            return "Person={__name:%s, __age:%s}" % (self.__name, self.__age)
    
        __repr__ = __str__
    
    
    p = Person("abc", 99)
    serialized_data = json.dumps(p, default=lambda obj: obj.__dict__)
    print(serialized_data)
    # {"_Person__name": "abc", "_Person__age": 99}
    

    注意:

    1. 上面指定default,就是指定序列化时对象数据的处理方式;
    2. 类变量没有被序列化,只有对象的属性被序列化了
    3. 被序列化的对象,是内部转换后的,也就是私有的属性都加上_类名

    上面的方式虽然也能实现序列化,但是序列化后的结果其实并不理想,字段名称比较特殊,而且所有属性都序列化了,不能隐藏一些属性;所以我们可以自定义序列化方式,示例如下:

    import json
    
    class Person:
        level = "high"
    
        def __init__(self, name, age):
            self.__name = name
            self.__age = age
    
        def __str__(self):
            return "Person={__name:%s, __age:%s}" % (self.__name, self.__age)
    
        __repr__ = __str__
    
        @property
        def name(self):
            return self.__name
    
        @property
        def age(self):
            return self.__age
    
    
    # 定义person类的序列化规则
    def person_serialize_rule(person_obj):
        # 要返回哪些字段、字段值要进行什么转换、都可以在这里自定义
        return {
            "name": person_obj.name,
            "age": person_obj.age
        }
    
    
    p = Person("abc", 99)
    # 指定序列化规则
    serialized_data = json.dumps(p, default=person_serialize_rule)
    print(serialized_data)
    # {"age": 99, "name": "abc"}
    

    Json反序列化基本类型

    使用loads()接口,传入json格式的字符串数据即可,需要注意的是,Json中在括字符串的引号要用双引号。

    import json
    
    arr = "[1, 2, 3, 4, 5, 6]"
    deserialized_data = json.loads(arr)
    print(deserialized_data)
    # [1, 2, 3, 4, 5, 6]
    
    dt = '{"xyz": 456, "abc": "123", "789": "999"}'
    deserialized_data = json.loads(dt)
    print(deserialized_data)
    # {u'xyz': 456, u'abc': u'123', u'789': u'999'}
    

    Json反序列化自定义类型

    前面序列化自定义类型,自定义了序列化的规则,那么在反序列化的时候,同样需要自定义反序列化规则,比如将JSON中的哪个key对应到对象的哪个属性,字段值进行什么转换...

    自定义类型反序列化时,是将json数据反序列化为dict,自定义的规则只需要指定对象的哪些属性对应到dict的哪个key即可;

    指定反序列化规则-> object_hook示例如下:

    import json
    
    class Person:
        level = "high"
    
        def __init__(self, name, age):
            self.__name = name
            self.__age = age
    
        def __str__(self):
            return "Person={__name:%s, __age:%s}" % (self.__name, self.__age)
    
        __repr__ = __str__
    
    
    # 定义person类的反序列化规则
    def person_deserialize_rule(dt):
        # 将字典中的值,传递给__init__()
        return Person(name=dt.get("____name"), age=dt.get("age_"))
    
    
    # 为了演示,将key做了一些处理
    json_data = '{"age_": 99, "____name": "abc"}'
    deserialize_data = json.loads(json_data, object_hook=person_deserialize_rule)
    print(deserialize_data)
    # Person={__name:abc, __age:99}
    

    json文件数据的序列化与反序列化

    使用json.dump()json.load()这俩接口即可,如果是自定义类型,指定一下序列化规则和反序列化规则即可。

    import json
    
    class Person:
        level = "high"
    
        def __init__(self, name, age):
            self.__name = name
            self.__age = age
    
        def __str__(self):
            return "Person={__name:%s, __age:%s}" % (self.__name, self.__age)
    
        __repr__ = __str__
    
        @property
        def name(self):
            return self.__name
    
        @property
        def age(self):
            return self.__age
    
    
    ############ 测试序列化到文件中 ###############
    
    # 定义person类的序列化规则
    def person_serialize_rule(person_obj):
        # 要返回哪些字段、字段值要进行什么转换、都可以在这里自定义
        return {
            "name": person_obj.name,
            "age": person_obj.age
        }
    
    
    fd = None
    try:
        # 写入的文件
        fd = open("person.json", "w")
    
        p = Person("abc", 99)
        json.dump(p, fd, default=person_serialize_rule)
    finally:
        if fd:
            fd.close()
    
    
    ############ 测试从文件中读取数据进行反序列化 ###############
    
    # 定义person类的反序列化规则
    def person_deserialize_rule(dt):
        # 将字典中的值,传递给__init__()
        return Person(name=dt.get("name"), age=dt.get("age"))
    
    
    try:
        fd = open("person.json", "r")
        deserialize_data = json.load(fd, object_hook=person_deserialize_rule)
        print(deserialize_data)
        # Person={__name:abc, __age:99}
    finally:
        if fd:
            fd.close()
    

    原文地址:https://www.cnblogs.com/-beyond/p/15376680.html
    转载请先获得许可!!!

    如需转载,请注明文章出处,谢谢!!!
  • 相关阅读:
    Dart Learn Notes 04
    Dart Learn Notes 03
    Dart Learn Notes 02
    一介书生,仅此而已
    计算机技术的演进及编程语言的多样
    C#方法(用法,参数)
    C#数组--(Array类的属性和方法)
    C#数组--(一维数组,二维数组的声明,使用及遍历)
    程序设计的编程方法
    C#流程控制语句--跳转语句(break,continue,goto,return,)
  • 原文地址:https://www.cnblogs.com/-beyond/p/15376680.html
Copyright © 2020-2023  润新知