序列化
一、序列化、反序列化、持久化?
将内存中的对象转换为可通过网络传输或可以存储到本地磁盘的数据格式(如:XML、JSON或特定格式的字节串)的过程称为序列化;反之,则称为反序列化。
持久化和序列化很相似,有些人甚至会混为一谈,其实还是有区别的:
序列化是为了解决对象的网络传输问题,而持久化是为了解决对象的存储问题,可以利用序列化来辅助持久化(对象先序列化,再持久化),可以说凡是可以持久化的对象都可以序列化。
在Python中用于序列化(或者说是持久化)和反序列化的3个模块:json & pickle & shelve。
二、json 模块
1、dumps() 序列化和 loads() 反序列化
dumps() 序列化
1
2
3
4
5
6
7
8
9
10
11
12
13
|
import json #导入json模块 info = { 'name' : "zhangqigao" , "age" : 22 } with open ( "test.txt" , "w" ) as f: #以普通模式写入 data = json.dumps(info) #把内存对象转为字符串 f.write(data) #写到文件中 #text.txt文件中的内容 { "name" : "zhangqigao" , "age" : 22 } |
loads() 反序列化
1
2
3
4
5
6
7
8
9
|
import json with open ( "test.txt" , "r" ) as f: #以普通模式读 data = json.loads(f.read()) #用loads反序列化 print (data.get( "age" )) #输出 22 |
2、dump() 序列化和 load() 反序列化
dump() 序列化
1
2
3
4
5
6
7
8
9
10
11
12
|
import json info = { 'name' : "zhangqigao" , "age" : 22 } with open ( "test.txt" , "w" ) as f: #文件以写的方式打开 json.dump(info,f) #第1个参数是内存的数据对象 ,第2个参数是文件句柄 #text.txt文件中的内容 { "name" : "zhangqigao" , "age" : 22 } |
load() 反序列化
1
2
3
4
5
6
7
8
9
|
import json with open ( "test.txt" , "r" ) as f: #以读的方式打开文件 data = json.load(f) #输入文件对象 print (data.get( "age" )) #输出 22 |
3、序列化函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
import json def sayhi(name): #函数 print ( "name:" ,name) info = { 'name' : "zhangqigao" , "age" : 22 , "func" :sayhi #引用sayhi函数名 } with open ( "test.txt" , "w" ) as f: json.dump(info,f) #序列化info数据对象 #输出 File "D:\Python\Python35\lib\json\encoder.py" , line 403 , in _iterencode_dict yield from chunks File "D:\Python\Python35\lib\json\encoder.py" , line 436 , in _iterencode o = _default(o) File "D:\Python\Python35\lib\json\encoder.py" , line 179 , in default raise TypeError( repr (o) + " is not JSON serializable" ) TypeError: <function sayhi at 0x00000000006DD510 > is not JSON serializable #不支持jsom序列化 |
小结:
- dumps() 和 loads() 是成对使用的,dump() 和 load() 是成对使用的。
- dumps() 和 loads() 由于序列化的是内容,所以后面要加s,但是 dump() 和 load() 序列化的内容是对象,所以是单数。
- json 只能处理简单的数据类型,例如:字典、列表、字符串等,不能处理函数等复杂的数据类型。
- json 是所有语言通用的,所有语言都支持json,如果我们需要python跟其他语言进行数据交互,那么就用 json 格式。
二、pickle 模块
1、dumps() 序列化和 loads() 反序列化
dumps() 序列化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
import pickle info = { 'name' : "zhangqigao" , "age" : 22 , } with open ( "test.txt" , "wb" ) as f: #以二进制的形式写入 data = pickle.dumps(info) #序列化成字符串 f.write(data) #写入test.txt 文件中 #输出到test.txt文件中的内容 �}q (X ageqKX nameqX zhangqigaoqu. |
loads() 反序列化
1
2
3
4
5
6
7
8
9
|
import pickle with open ( "test.txt" , "rb" ) as f: #以二进制的模式读 data = pickle.loads(f.read()) #反序列化操作 print (data.get( "age" )) #输出 22 |
2、dump() 序列化和 load() 反序列化
dump() 序列化
1
2
3
4
5
6
7
8
9
10
11
12
13
|
import pickle info = { 'name' : "zhangqigao" , "age" : 22 , } with open ( "test.txt" , "wb" ) as f: pickle.dump(info,f) #序列化 #输出 �}q (X ageqKX nameqX zhangqigaoqu. |
load() 反序列化
1
2
3
4
5
6
7
8
9
|
import pickle with open ( "test.txt" , "rb" ) as f: data = pickle.load(f) #反序列化成内存对象 print (data.get( "age" )) #输出 22 |
从上面的结果观察,json 和 pickle 好像也没什么区别?但是别忘了,我们说,json 只能序列化简单的数据类型,而 pickle 可以序列化python中所有的数据类型,包括函数、类等,下面我们就来看看,如何序列化函数的。
还有就是,pickle 序列化的是字节(打开文件时需要使用二进制模式wb、rb),而 json 序列化的是字符,这个要注意一下。
3、序列化函数
①序列化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
import pickle def sayhi(name): #函数 print ( "hello:" ,name) info = { 'name' : "zhangqigao" , "age" : 22 , "func" :sayhi #"func"对应的值sayhi,是函数名 } with open ( "test.txt" , "wb" ) as f: data = pickle.dumps(info) f.write(data) #输出test.txt �}q (X funcqc__main__ sayhi qX ageqKX nameqX zhangqigaoqu. |
②反序列化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
import pickle def sayhi(name): #在反序列化中必须写上此函数,不然会报错,因为在加载的时候,函数没有加载到内存 print ( "hello:" ,name) with open ( "test.txt" , "rb" ) as f: data = pickle.loads(f.read()) print (data.get( "age" )) data.get( "func" )( "zhangqigao" ) #执行函数sayhi #输出 22 hello: zhangqigao #输出的函数体中的逻辑也是可以变的,这边我就不做演示了 |
小结:
- json只支持简单的数据类型,pickle 支持所有的数据类型。
- pickle 只能支持 Python 本身的序列化和反序列化,不能用作和其他语言做数据交互,json跨语言。
- pickle 序列化的是整个的数据对象,所以反序列化函数时,函数体中的逻辑变了,是跟着新的函数体走的。
- pickle 和 json 在Python3中,一个文件只能 dump 一次和 load 一次,在Python2.7里面可以 dump 多次,load 多次,anyway,以后只记住,在一个文件中只需要 dump 一次,load 一次就可以了。
三、shelve 模块
之前我们说不管是json也好,还是pickle也好,在Python3中只能 dump() 一次和 load() 一次,不能 dump()多次,和 load() 多次,但是我们真想要 dump() 多次和 load() 多次怎么办呢,今天我们就来说说这个 shelve 模块。
shelve是一个简单的数据存储方案,类似key-value数据库,可以很方便的保存Python对象,其内部是通过pickle协议来实现数据序列化。
shelve只有一个open()函数,这个函数用于打开指定的文件(一个持久的字典),然后返回一个shelf对象。shelf是一种持久的、类似字典的对象。
1、持久化
1
2
3
4
5
6
7
8
9
10
11
12
13
|
import shelve #导入shelve模块 def stu_data(name,age): #定义一个函数 print ( "register stu:" ,name,age) name = [ "test" , "zhang" , "qi" , "gao" ] #定义一个列表 info = { "name" : "zhangqigao" , "age" : 18 } #定义一个字典 with shelve. open ( "shelve_test" ) as d: d[ "test" ] = name #持久化列表 d[ "info" ] = info #持久化字典 d[ "func" ] = stu_data #持久化函数 |
代码执行结果:
生成三个文件夹,分别是:shelve_test.dir、shelve_test.dat、shelve_test.bak
①shelve_test.dir内容
1
2
3
|
'test' , ( 0 , 50 ) 'func' , ( 1024 , 24 ) 'info' , ( 512 , 48 ) |
②shelve_test.dat内容
1
2
3
4
5
6
|
�]q (X testqX zhangqX qiqX gaoqe. �}q (X nameqX zhangqigaoqX ageqKu. �c__main__ stu_data q . |
③shelve_test.bak内容
1
2
3
|
'test' , ( 0 , 50 ) 'func' , ( 1024 , 24 ) 'info' , ( 512 , 48 ) |
2、解析文件内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
import shelve def stu_data(name,age): #这边一定要定义相同名字的函数,不然执行报错 print ( "stu:" ,name,age) with shelve. open ( "shelve_test" ) as f: print (f[ 'test' ]) #解析列表 print (f[ 'info' ]) #解析字典 print (f[ "func" ]( "zhangqsan" , 22 )) #解析函数 #输出 [ 'test' , 'zhang' , 'qi' , 'gao' ] { 'age' : 18 , 'name' : 'zhangqigao' } stu: zhangqsan 22 None |
3、常用方法
1
2
3
4
5
6
7
8
9
10
11
12
|
>>> import shelve >>> d = shelve. open ( "shelve_test" ) >>> dir (d) [ '_MutableMapping__marker' , '__abstractmethods__' , '__class__' , '__contains__' , '__del__' , '__delattr__' , '__delitem__' , '__dict__' , '__dir__' , '__doc__' , '__enter__' , '__eq__' , '__exit__' , '__format__' , '__ge__' , '__getattribute__' , '__getitem__' , '__gt__' , '__hash__' , '__init__' , '__iter__' , '__le__' , '__len__' , '__lt__' , '__module__' , '__ne__' , '__new__' , '__reduce__' , '__reduce_ex__' , '__repr__' , '__setattr__' , '__setitem__' , '__sizeof__' , '__slots__' , '__str__' , '__subclasshook__' , '__weakref__' , '_abc_cache' , '_abc_negative_cache' , '_abc_negative_cache_version' , '_abc_registry' , '_protocol' , 'cache' , 'clear' , 'close' , 'dict' , 'get' , 'items' , 'keyencoding' , 'keys' , 'pop' , 'popitem' , 'setdefault' , 'sync' , 'update' , 'values' , 'writeback' ] |
3.1、update
说明:update方法是如果序列化的值存在,则更新,如果不存在,则新增,用法:update({key:序列化对象})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
#dumps到文件中 import shelve info = { "name" : "zhangqigao" , "age" : 18 } with shelve. open ( "shelve_test" ) as d: d[ 'qigaotest' ] = info #变量存在 d.update({ 'qigaotest' : "shuaigaogao" }) #更新已经key为"qigaotest"的值 #loads到内存中 import shelve with shelve. open ( "shelve_test" ) as f: print (f.get( "qigaotest" )) #输出 shuaigaogao |
3.2、get
说明:把文件中的值load到内存中时,通过get它的key值获取
1
2
3
4
5
6
7
|
import shelve with shelve. open ( "shelve_test" ) as f: print (f.get( "qigaotest" )) #或者是f["qigaotest"] #输出 shuaigaogao |
注意:如果是通过f["qigaotest"]这种方法取,如果值不存在则会报错,通过get去取,不存在,则会返回none
小结:
- shelve 模块是一个简单的key,value将内存数据通过文件持久化的模块。
- shelve 模块可以持久化任何pickle可支持的python数据格式。
- shelve 模块就是 pickle 模块的一个封装。
- shelve 模块在一个文件中是可以多次 dump 和 load。