【python】 序列化之 Json 、 Pickle、Shelve 模块
序列化:将对象转变成可存储到本地磁盘或可通过网络传输的数据格式过程称之为序列化,将数据类型转换成字符串的过程。
反序列化:将字符串转换成数据类型的过程。
作用
将内存中的各种数据类型的数据保存到本地磁盘持久化:
程序在运行的过程中,所有的变量都是在内存中操作的,当程序执行完毕,变量占有的内存就会被操作系统回收,因此若我们需要将某些数据持久化管理,需要存储在磁盘中,下次运行从磁盘中读取数据,故需要进行序列化操作,才能将变量存储到磁盘上。
将内存中的各种数据类型的数据通过网络传输给其他客户端:
若想将一个系统内的数据通过网络传输给其他系统,通常需要将这些数据转化成字符串,网络通过bytes进行传输,在传输过程中,需先将数据类型转换成字符串,进而转换成bytes类型,完成传输。
应用场景
-
数据存储:文件和数据库均是以字符串形式写入,在写入过程中,需将数据类型转化成字符串形式,即进行序列化操作,若需要读取,则进行反序列化操作。
-
网络传输
不使用模块实现序列化和反序列化
序列化:将字典变成字符串类型
1 d = {'key1': 'value1', 'key2': 'value2'} 2 print(str(d), type(str(d)))
# {'key1': 'value1', 'key2': 'value2'} <class 'str'>
反序列化 :将字符串变成字典类型
print(eval(str(d)), type(eval(str(d))))
# {'key1': 'value1', 'key2': 'value2'} <class 'dict'>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 import json 2 3 i = 6 4 st_i = json.dumps(i) 5 print("int类型序列化:%s" % st_i, type(st_i)) # int类型序列化:6 <class 'str'> 6 7 i = json.loads(st_i) 8 print("loads反序列化为int类型:%s" % i, type(i)) # loads反序列化为int类型:6 <class 'int'>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 s = 'a' 2 st_s = json.dumps(s) 3 print("str类型序列化:%s" % st_s, type(st_s)) # str类型序列化:"a" <class 'str'> 4 5 s = json.loads(st_s) 6 print("loads反序列化为str类型:%s" % s, type(s)) # loads反序列化为str类型:a <class 'str'>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 li = [1, 'a', 2, 'b'] 2 st_li = json.dumps(li) 3 print("list类型序列化:%s" % st_li,type(st_li)) # list类型序列化:[1, "a", 2, "b"] <class 'str'> 4 5 li = json.loads(st_li) 6 print("loads反序列化为list类型:%s" % li, type(li)) # loads反序列化为list类型:[1, 'a', 2, 'b'] <class 'list'>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 dic = {'key1': 'value1', 'key2': 'value2'} 2 st_dic = json.dumps(dic) 3 print("dict类型序列化:%s" % st_dic, type(st_dic)) 4 # dumps序列化:{"key1": "value1", "key2": "value2"} <class 'str'> 5 6 dic = json.loads(st_dic) 7 print("loads反序列化为dict类型:%s" % dic, type(dic)) 8 # loads反序列化为dict类型:{'key1': 'value1', 'key2': 'value2'} <class 'dict'>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 # dump(obj,文件句柄) 2 dic = {'key1': 'value1', 'key2': 'value2'} 3 with open('json_sample', 'w') as f: 4 json.dump(dic, f) # 将数据结构序列化后写入文件中 5 print("使用dump序列化,文件写入成功") 6 7 # load(文件句柄) 8 with open('json_sample', 'r') as f: 9 dic = json.load(f) # 只能读取一个字典,如果有多个字典,先一个一个取出来再反序列 10 print("使用load反序列化,取出文件中的内容:%s" % dic, type(dic)) # 从文件中获取并反序列化
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 # dumps() 2 dic = {'username': ['李华', '二愣子'], 'sex': 'male', 'age': 16} 3 dic = {'key1': 'value1', 'key2': 'value2'} 4 st = pickle.dumps(dic) 5 print("dumps序列化成二进制:%s" % st, type(st)) # 返回bytes类型数据 6 7 # dumps序列化成二进制:b'\x80\x03}q\x00(X\x04\x00\x00\x00key1q\x01X\x06\x00\x00\x00value1q\x02X\x04\x00\x00\x00key2q\x03X\x06\x00\x00\x00value2q\x04u.' <class 'bytes'> 8 9 # loads() 10 dic = pickle.loads(st) 11 print("反序列化:%s" % dic, type(dic)) 12 13 # 反序列化:{'key1': 'value1', 'key2': 'value2'} <class 'dict'> 14 15 # dump() 16 data = {'key1': 'value1', 'key2': 'value2'} 17 with open('json_sample', 'wb') as f: # 序列化转换成二进制,故要使用wb写入 18 pickle.dump(data, f) 19 with open('json_sample', 'rb') as f: 20 dic = pickle.load(f) 21 print(dic) 22 23 # {'key1': 'value1', 'key2': 'value2'}
优势:使用序列化句柄能直接操作,简便
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 # 序列化 2 f = shelve.open('shelve_sample') 3 f['key'] = {'a': 1, 'b': 2} 4 f.close() 5 6 # 反序列化 7 f = shelve.open('shelve_sample') 8 print(f['key']) # {'a': 1, 'b': 2}
Json VS Pickle VS Shelve
-
Json是文本序列化格式,Pickle是二进制序列化格式;
-
Json是轻量级的数据交互方式,体积小,Pickle存储数据占用空间大;
-
Json是通用的数据格式,Pickle专为python设计,序列化只有python能理解;
-
Json只支持python部分的数据类型(int/str/list/dict/tuple),pickle支持python所有的数据类型;
-
Shelve操作简便,使用序列化句柄就能直接操作,但执行后会生成三份文件,不知道这是好处还是坏处,pickle和shelve写入的文件数据不便于阅读,或者说看不懂。
问题:json序列化只支持一次性写入,一次性读取,但文件操作建议分步写入数据,若一次性写入庞大的json数据,占用内存大,最好是能获取一条数据写入一条数据。
解决:每次dumps一条数据,在数据后面加\n换行,每条数据写一行,读文件时一行一行读,对每行字符串进行loads。
1 li = [{'a': 1}, {'b': 2}, {'c': 3}] 2 with open("json_sample", 'w', encoding="utf-8") as f: 3 for i in li: 4 str_dic = json.dumps(i) 5 f.write(str_dic+'\n') 6 7 with open("json_sample", 'r', encoding="utf-8") as f: 8 for line in f: 9 dic = json.loads(line.strip()) 10 print(dic)