Python-使用pickle和json进行序列化和反序列化
原文地址:https://www.cnblogs.com/-beyond/p/15376680.html
转载请先获得许可!!!
python序列化与反序列化介绍
序列化和反序列化,就是数据的格式转换,是相对的,一般是这样定义的:
- 将数据由X格式转换为Y格式,叫做序列化
- 将数据由Y格式转换为X格式,叫做反序列化
常用的格式,比如xml、json、yaml、二进制;
常用的序列化方式,比如json、二进制、hassian、protobuf、thrift....
Python
内置了一种数据序列化和反序列化的方式,也就是使用pickle模块,这个pickle
模块将数据序列化后的内容,对于人来说是无法阅读的,但是使用pickle的反序列化,是能够将其解析为原始数据的,另外,pickle
是python
的,其他编程语言无法处理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
一样:
dumps()
,将数据序列化后存到内存里面;dump()
则是将数据序列化后保存到文件中;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}
注意:
- 上面指定
default
,就是指定序列化时对象数据的处理方式; - 类变量没有被序列化,只有对象的属性被序列化了
- 被序列化的对象,是内部转换后的,也就是私有的属性都加上
_类名
上面的方式虽然也能实现序列化,但是序列化后的结果其实并不理想,字段名称比较特殊,而且所有属性都序列化了,不能隐藏一些属性;所以我们可以自定义序列化方式,示例如下:
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
转载请先获得许可!!!