python3内置持久化模块pickle心得
本文环境: Windows 10 专业版 64 位 + Thonny 3.2.6
内置模块 pickle (泡菜)可以将文件对象转换为 bytes 字节格式,以便于在python程序间或网络传输;内置模块 pickle 可以将 python 文件对象转换为 python 专用格式存储到硬盘以便于持久保存。
模块 pickle 可以处理:
所有python支持的原生类型:布尔值,整数,浮点数,复数,字符串,字节,None 。
由任何原生类型组成的列表,元组,字典和集合。
将对象转换 pickle.dumps() 为 bytes 字节格式和从 bytes 字节对象中读取 pickle.loads()
pickle.dumps(obj) :以字节对象形式返回封装的对象,不需要写入文件中。
pickle.loads(bytes_object) : 从字节对象中读取被封装的对象,并返回。
实例代码:
# pickle.dumps() pickle.loads() 训练
import pickle # 导入模块 pickle
my_str = "abcdef"
my_list = [1,2,3,4,5]
my_tuple = (100,200)
my_dict = {"name":"qs","age":18}
data1 = pickle.dumps(my_str)
print("pickle.dumps(my_str) 生成的数据内容:",data1)
print("pickle.dumps(my_str) 生成的数据格式:",type(data1))
data2 = pickle.loads(data1)
print("pickle.loads(data2) 生成的数据内容:",data2)
print("\n")
data1 = pickle.dumps(my_list)
print("pickle.dumps(my_list) 生成的数据内容:",data1)
print("pickle.dumps(my_list) 生成的数据格式:",type(data1))
data2 = pickle.loads(data1)
print("pickle.loads(data2) 生成的数据内容:",data2)
print("\n")
data1 = pickle.dumps(my_tuple)
print("pickle.dumps(my_tuple) 生成的数据内容:",data1)
print("pickle.dumps(my_tuple) 生成的数据格式:",type(data1))
data2 = pickle.loads(data1)
print("pickle.loads(data2) 生成的数据内容:",data2)
print("\n")
data1 = pickle.dumps(my_dict)
print("pickle.dumps(my_dict) 生成的数据内容:",data1)
print("pickle.dumps(my_dict) 生成的数据格式:",type(data1))
data2 = pickle.loads(data1)
print("pickle.loads(data2) 生成的数据内容:",data2)
结果:
>>> %Run pickle_test.py
pickle.dumps(my_str) 生成的数据内容: b'\x80\x03X\x06\x00\x00\x00abcdefq\x00.'
pickle.dumps(my_str) 生成的数据格式: <class 'bytes'>
pickle.loads(data2) 生成的数据内容: abcdef
pickle.dumps(my_list) 生成的数据内容: b'\x80\x03]q\x00(K\x01K\x02K\x03K\x04K\x05e.'
pickle.dumps(my_list) 生成的数据格式: <class 'bytes'>
pickle.loads(data2) 生成的数据内容: [1, 2, 3, 4, 5]
pickle.dumps(my_tuple) 生成的数据内容: b'\x80\x03KdK\xc8\x86q\x00.'
pickle.dumps(my_tuple) 生成的数据格式: <class 'bytes'>
pickle.loads(data2) 生成的数据内容: (100, 200)
pickle.dumps(my_dict) 生成的数据内容: b'\x80\x03}q\x00(X\x04\x00\x00\x00nameq\x01X\x02\x00\x00\x00qsq\x02X\x03\x00\x00\x00ageq\x03K\x12u.'
pickle.dumps(my_dict) 生成的数据格式: <class 'bytes'>
pickle.loads(data2) 生成的数据内容: {'name': 'qs', 'age': 18}
>>>
个人猜想:dumps 和 loads 尾部的 s 是字节模式的意思,字节在内容中是以 str 的形式存储的。
将文件对象的内容写入硬盘 pickle.dump() 并读取 pickle.load()
内置模块 pickle 工作时会把文件先转换为字节序列,所以在使用内置函数 open() 新建和打开文件时要使用 “wb” 字节写模式和 “rb” 字节读模式。
将文件对象的内容写入磁盘 pickle.dump() 语法:
pickle.dump(obj, file[, protocol])
参数说明:
obj :必填参数。准备写入 file 文件对象的数据对象。
模块 pickle 可以处理:
所有python支持的原生类型:布尔值,整数,浮点数,复数,字符串,字节,None 。
由任何原生类型组成的列表,元组,字典和集合。
file :必填参数。obj 准备写入的文件对象,这个 file 文件对象一般是用 python 内置函数 open(“wb”) 字节写模式创建的。
protocol :可选参数。 pickle 使用的协议,支持的协议有0,1,2,3,默认的协议(该参数不写时)是添加在Python 3中的协议3。
关于protocol的说明原文及机器翻译:
Protocol version 0 is the original “human-readable” protocol and is backwards compatible with earlier versions of Python.
Protocol version 0是原始的“人类可读”协议,并向后兼容Python的早期版本。
Protocol version 1 is an old binary format which is also compatible with earlier versions of Python.
Protocol version 1是一种旧的二进制格式,它也与早期版本的Python兼容。
Protocol version 2 was introduced in Python 2.3. It provides much more efficient pickling of new-style classes. Refer to PEP 307 for information about improvements brought by protocol 2.
协议版本2是在Python 2.3中引入的。它为新类型的类提供了更有效的腌制。有关协议2带来的改进的信息,请参阅PEP 307。
Protocol version 3 was added in Python 3.0. It has explicit support for bytes objects and cannot be unpickled by Python 2.x. This is the default protocol, and the recommended protocol when compatibility with other Python 3 versions is required.
协议版本3是在Python 3.0中添加的。它对bytes对象有显式支持,并且不能被Python 2.x取消pickle。这是默认协议,当需要与其他Python 3版本兼容时,这是推荐的协议。
Protocol version 4 was added in Python 3.4. It adds support for very large objects, pickling more kinds of objects, and some data format optimizations. Refer to PEP 3154 for information about improvements brought by protocol 4.
协议版本4是在Python 3.4中添加的。它增加了对非常大的对象的支持,对更多类型的对象的筛选,以及一些数据格式的优化。有关协议4带来的改进的信息,请参阅PEP 3154。
从磁盘读取 pickle.load() 语法:
pickle.load(file,*,fix_imports=True, encoding=”ASCII”, errors=”strict”)
参数说明:
file :必填参数。准备从磁盘 file文件对象读取数据的对象。这个 file 文件对象是要由 pick.dump() 生成的。这个 file 文件对象一般是用 python 内置函数 open(“rb”) 字节读模式打开的。
剩余的参数都是可选参数。
pickle.dump() pickle.load() 上机代码:
# 模块 pickle 训练
import pickle
my_str = "abcde"
my_list = [1,2,3,4,5]
my_tuple = ('a','b','c','d','e')
my_dict = {'name':'qs','age':43}
# 生成 pickle 数据到硬盘
# 在本地磁盘新建一个名为 pickle_test 的文件
file_object = open("pickle_test","wb") # 要用 "wb" 模式
# 模块 pickle 的方法 dump() 写入数据
# 由于模块 pickle 会把数据转化为字节流模式,写入 pickle 文件需要用 'wb' 字节模式。
pickle.dump(my_str,file_object) # 写入了第1行 pickle 格式的数据
pickle.dump(my_list,file_object) # 写入了第2行 pickle 格式的数据
pickle.dump(my_tuple,file_object) # 写入了第3行 pickle 格式的数据
pickle.dump(my_dict,file_object) # 写入了第4行 pickle 格式的数据
file_object.close()
# 用模块 pickle 的方法 load() 读取模块 pickle 保存的数据
# 由于模块 pickle 会把数据转化为字节流模式,读取 pickle 文件需要用 'rb' 字节模式。
file_object = open("pickle_test","rb") # 要用 "rb" 模式
contents1 = pickle.load(file_object)
print(contents1) # "abcde"
contents2 = pickle.load(file_object)
print(contents2) # [1,2,3,4,5]
contents3 = pickle.load(file_object)
print(contents3) # ('a','b','c','d','e')
contents4 = pickle.load(file_object)
print(contents4) # {'name':'qs','age':43}
print("""以上输出表示模块 pickle 可以将 python 的大多数对象持久化。
模块 pickle (泡菜)就是像制作泡菜一样,
dump() 时,一条一条的写入硬盘。
load() 时,一条一条的从硬盘读取出来。""")
file_object.close()
结果:
>>> %Run pickle_test.py
abcde
[1, 2, 3, 4, 5]
('a', 'b', 'c', 'd', 'e')
{'name': 'qs', 'age': 43}
以上输出表示模块 pickle 可以将 python 的大多数对象持久化。
模块 pickle (泡菜)就是像制作泡菜一样,
dump() 时,一条一条的写入硬盘。
load() 时,一条一条的从硬盘读取出来。
>>>
在 py 文件的文件夹中可以找到生成的 pickle_test 文件,使用记事本打开内容如下:
€X abcdeq .€]q (KKKKKe.€(X aq X bqX cqX dqX eqtq.€}q (X nameqX qsqX ageqK+u.
截图如下:
猜想 python 用 pickle (泡菜)作为模块名字的原因
上个例子中 pickle.dump() 了4条数据,如果在以上代码的第32行中加入以下代码,
contents5 = pickle.load(pickle_data)
print(contents5)
在 pickle.load() 读取4条数据之后,尝试继续 pickle.load() 读取 pickle_test 文件的内容,系统将会提示错误。
完整代码如下:
# 模块 pickle 训练
import pickle
my_str = "abcde"
my_list = [1,2,3,4,5]
my_tuple = ('a','b','c','d','e')
my_dict = {'name':'qs','age':43}
# 生成 pickle 数据到硬盘
# 在本地磁盘新建一个名为 pickle_test 的文件
pickle_data = open("pickle_test","wb")
# 模块 pickle 的方法 dump() 写入数据
# 由于模块 pickle 会把数据转化为字节流模式,写入 pickle 文件需要用 'wb' 字节模式。
pickle.dump(my_str,pickle_data) # 写入了第1行 pickle 格式的数据
pickle.dump(my_list,pickle_data) # 写入了第2行 pickle 格式的数据
pickle.dump(my_tuple,pickle_data) # 写入了第3行 pickle 格式的数据
pickle.dump(my_dict,pickle_data) # 写入了第4行 pickle 格式的数据
pickle_data.close()
# 用模块 pickle 的方法 load() 读取模块 pickle 保存的数据
# 由于模块 pickle 会把数据转化为字节流模式,读取 pickle 文件需要用 'rb' 字节模式。
pickle_data = open("pickle_test","rb")
contents1 = pickle.load(pickle_data)
print(contents1) # "abcde"
contents2 = pickle.load(pickle_data)
print(contents2) # [1,2,3,4,5]
contents3 = pickle.load(pickle_data)
print(contents3) # ('a','b','c','d','e')
contents4 = pickle.load(pickle_data)
print(contents4) # {'name':'qs','age':43}
contents5 = pickle.load(pickle_data)
print(contents5) # EOFError: Ran out of input
print("""以上输出表示模块 pickle 可以将 python 的大多数对象持久化。
模块 pickle (泡菜)就是像制作泡菜一样,
dump() 时,一条一条的写入硬盘。
load() 时,一条一条的从硬盘读取出来。""")
pickle_data.close()
结果:
>>> %Run pickle_test.py
abcde
[1, 2, 3, 4, 5]
('a', 'b', 'c', 'd', 'e')
{'name': 'qs', 'age': 43}
[Could not import friendly_traceback. You can install it with Tools => Manage packages]
Traceback (most recent call last):
File "E:\test\pickle_test.py", line 32, in <module>
contents5 = pickle.load(pickle_data)
EOFError: Ran out of input
>>>
结果分析:
从文件中读取数据时,文件已经读取到末尾,再次尝试读取。
模块 pickle 和腌制泡菜一样, pickle.dump() 序列化数据时,一条一条的处理,pickle.load() 反序列化数据时,也是一条一条处理,先被处理的数据先取出。
使用语句try-except 处理 EOFError: Ran out of input
如果我们不知道 pickle.load() 生成的文件的内容有多少,可以使用循环 while 遍历 pickle.load()生成的文件,使用语句 try-except 处理 EOFError:Ran out of input 。实例如下:
# 模块 pickle 训练
import pickle
my_str = "abcde"
my_list = [1,2,3,4,5]
my_tuple = ('a','b','c','d','e')
my_dict = {'name':'qs','age':43}
# 生成 pickle 数据到硬盘
# 在本地磁盘新建一个名为 pickle_test 的文件
file_object = open("pickle_test","wb") # 要用 "wb" 模式
# 模块 pickle 的方法 dump() 写入数据
# 由于模块 pickle 会把数据转化为字节流模式,写入 pickle 文件需要用 'b' 字节模式。
pickle.dump(my_str,file_object) # 写入了第1行 pickle 格式的数据
pickle.dump(my_list,file_object) # 写入了第2行 pickle 格式的数据
pickle.dump(my_tuple,file_object) # 写入了第3行 pickle 格式的数据
pickle.dump(my_dict,file_object) # 写入了第4行 pickle 格式的数据
file_object.close()
with open("pickle_test","rb") as file_object:
print("文件输出开始:")
while 1:
try:
print(pickle.load(file_object))
except EOFError:
print("文件输出完毕,退出。")
break
结果:
>>> %Run pickle_test.py
文件输出开始:
abcde
[1, 2, 3, 4, 5]
('a', 'b', 'c', 'd', 'e')
{'name': 'qs', 'age': 43}
文件输出完毕,退出。
>>>