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
转载请先获得许可!!!

posted @ 2021-10-07 18:31  寻觅beyond  阅读(355)  评论(0编辑  收藏  举报
返回顶部