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
转载请先获得许可!!!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 字符编码:从基础到乱码解决
2017-10-07 CI框架2.x的验证码中所遇问题解决