说明:
- 有时候需要将list、dictionary、string、自己定义的数据对象保存在磁盘中。常规的file.write()方法,无论写入什么类型的内容,file.read()出来的结果都是字符串(string)。 我们更希望写入前是什么类型,读出后也是什么类型。pickle模块就能干这件事!
- pickle模型的核心功能是将对象序列化成一个Python 语言专用的二进制格式,同时也能反序列化回原来的对象,因此,该模块又叫序列化模块。pickle既可以将对象序列化在程序中,也可以序列化到文件中(即保存在文件中,正是我们想要的。)
- 注意:pickle后的结果是不可认读的(打开乱码),并只能用于Python环境,不能用作与其它语言进行数据交换。
import pickle
一. 将对象序列化到文件,再从文件反序列化成对象
用到的两个方法:
pickle.dump(obj, file, [,protocol]):
将数据“对象obj”,保存到“文件file”中,使用有3种协议,0为ASCII(默认),1为旧式二进制,2为新式二进制协议(更高效一些)。
pickle.load(file):
读取已经存在的序列化文件file中的内容,并将其反序列回obj对象。
下例中list a,用pickle.dumple()序列化进文件,再用pickle.load()反序列化,结果依然是list(包括内部元素的类型也没变)。而如果用普通的file.write()写入文件,无论写入的内容是什么类型,用file.read()打开返回的都是字符串类型'str',这对于后续处理是极为不利的。
a = ['A',100,['cat']]
with open('text.txt', 'wb') as file1:
pickle.dump(a, file1) # 将a写入文件
with open('text.txt', 'rb') as file2:
b = pickle.load(file2) # 直接从file2中获取数据
print(b,':' ,type(b))
print(b[0],':', type(b[0]))
print(b[1],':', type(b[1]))
print(b[2],':', type(b[2]))
输出:
['A', 100, ['cat']] : <class 'list'>
A : <class 'str'>
100 : <class 'int'>
['cat'] : <class 'list'>
注意:虽然上例中生成的文件是“text.txt”,但实际上是无法直接打开的二进制文件。
1.1 多个对象写入文件(序列化)和读取文件(反序列化)问题
pickle在使用过程由于其特殊的内容标记,使得文件dump()几次,就必须load()几次才能将数据全部读出来:
a=1
b=[2]
c={'name':'Lili'}
with open("text.txt","wb") as f:
pickle.dump(a,f)
pickle.dump(b,f)
pickle.dump(c,f)
with open("text.txt","rb") as f :
print(pickle.load(f)) # 输出q
# print(pickle.load(f)) # 输出b
# print(pickle.load(f)) # 输出c
输出:
1
实际中不可能记住所有的dump()次数,也就无法准确的使用load()多次的方式来取出值。
可以直接无限循环执行pickle.load(),直至其报错才停止:
# 接上面程序
with open("text.txt","rb") as f :
while True:
try:
print(pickle.load(f))
except:
break
输出:
1
[2]
{'name': 'Lili'}
1.2 反序列化时,对应类型的定义必须已经存在,否则出错
如下例,自定义了一个类Person,并生成了一个对象person1,利用pickle.dump()将其序列化进text.txt文件,然后利用pickle.load()将其反序列化,结果没问题。但是如果启用“del Person”这句代码将类的定义删除,则运行结果出错,因为在反序列化时无法为person1找到对应的类别定义。
# 定义一个类
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def show(self):
print(self.name+":"+str(self.age))
# 生成一个具体对象
person1= Person("Lili", 6)
person1.show()
# 利用pickle.dump()将对象person序列化到文件text.txt
with open('text.txt', 'wb') as f:
pickle.dump(person1, f, 0)
# del Person # 删除定义
# 利用pickle.load()从text.txt中反序列化对象person
with open('text.txt', 'rb') as f:
is_person = pickle.load(f)
is_person.show()
输出:
Lili:6
Lili:6
二. 将对象序列化,再反序列化成对象,但不写入文件
用到的两个方法:
pickle.dumps(obj, [, protocol]):
将obj对象序列化为string形式,而不存入文件,protocol默认为0。若为负值或HIGHEST_PROTOCOL,则使用最高的协议版本。
pickle.loads(string):
将前述序列化的string反序列化成obj。**
a = ['A',100,['cat']]
print('原始对象a:', a,';',type(a))
a_seqs = pickle.dumps(a) # 将a序列化(即转化成二进制)
print('a序列化结果:', a_seqs,';',type(a_seqs) )
a_back = pickle.loads(a_seqs) # 将序列化结果反序列化成a
print('a反序列化结果:', a_back,';',type(a_back) )
输出:
原始对象a: ['A', 100, ['cat']] ; <class 'list'>
a序列化结果: b'\x80\x04\x95\x14\x00\x00\x00\x00\x00\x00\x00]\x94(\x8c\x01A\x94Kd]\x94\x8c\x03cat\x94ae.' ; <class 'bytes'>
a反序列化结果: ['A', 100, ['cat']] ; <class 'list'>
参考:
https://www.cnblogs.com/ranxf/p/7800179.html
https://zhuanlan.zhihu.com/p/419362785
网友评论