首页 > 技术文章 > 【python】 序列化之 Json 、 Pickle、Shelve 模块

luwenqing 2021-03-03 14:08 原文

序列化&反序列化

初识

序列化:将对象转变成可存储到本地磁盘或可通过网络传输的数据格式过程称之为序列化,将数据类型转换成字符串的过程。

反序列化:将字符串转换成数据类型的过程。

 

作用

将内存中的各种数据类型的数据保存到本地磁盘持久化:

   程序在运行的过程中,所有的变量都是在内存中操作的,当程序执行完毕,变量占有的内存就会被操作系统回收,因此若我们需要将某些数据持久化管理,需要存储在磁盘中,下次运行从磁盘中读取数据,故需要进行序列化操作,才能将变量存储到磁盘上。

 

将内存中的各种数据类型的数据通过网络传输给其他客户端:

   若想将一个系统内的数据通过网络传输给其他系统,通常需要将这些数据转化成字符串,网络通过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'>

 

Json

描述:实现python数据类型与字符串之间的转换;

优势:在所有平台是通用的序列化格式,跨语言,体积小;

劣势:只有一部分类型的数据能转换成字符串(int/str/list/dict/tuple);

api:

dumps(obj) : 序列化,转换为json字符串(一般用于网络传输)

dump(obj,fp) : 序列化,转换并保存到json格式的文件中

loads(fp):反序列化,从json格式文件中读出数据(一般用于文件读写)

load(obj) : 反序列化

dumps 和 loads 序列化&反序列化

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'>
int类型使用json序列化&反序列化
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'>
str类型使用json序列化&反序列化
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'>
list类型使用json序列化&反序列化
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'>
dict类型使用json序列化&反序列化
tuple类型使用json序列化&反序列化

 

dump 和 load 序列化&反序列化输出到文件

 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))  # 从文件中获取并反序列化
Json之dump 和 load

 

Pickle

描述:实现python数据类型与python二进制的转换;

优势:专为python设计,支持python的所有数据类型进行序列化;

劣势:只能在python中使用,存储数据占用空间大;

api:

dumps():序列化,将对象转换成bytes对象

dump() :序列化,转换成bytes,至文件中,可以连续dump数据进入文件,然后连续load出来

loads():从bytes对象反序列化

load(): 对象反序列化,从文件读取数据

tip:使用dump()序列化时,打开文件必须以wb模式;使用load()反序列化时,打开文件必须以rb模式。

 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'}
Pickle之dumps、dump、loads、load

 

Shelve

描述:shelve是python提供的序列化方式

优势:使用序列化句柄能直接操作,简便

api:open()

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}
Shelve之序列化&反序列化

 

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)

 

推荐阅读