Python——第五章:pickle模块
序列化:把对象转化成二进制字节
反序列化:把二进制字节转化回对象
Pickle模块的常见用法:
Pickle.dunps 把对象(数据)转化成字节
Pickle.loads 把字节转化回对象(数据)
Pickle.dunp 把对象序列化成字节之后写入到文件
Pickle.load 把文件中的字节反序列化成对象
在Python中,序列化和反序列化是将数据结构转换为字节流或其他可存储或传输的格式,以及将字节流或其他格式还原为原始数据结构的过程。
序列化(Serialization)pickle.dumps
方法
序列化通常涉及将数据结构转换为字节流或字符串的过程,以便将其保存到文件、数据库或通过网络传输。
pickle.dumps(obj, protocol=None, *, fix_imports=True, buffer_callback=None)
:
- 作用:将一个对象序列化为一个字节对象。
- 使用场景:通常用于在内存中处理对象,比如将对象传递给网络通信、存储到数据库,或在需要字节对象的地方使用。
- 返回值:返回序列化后的字节对象。
序列化(Serialization)pickle.dump
方法
pickle.dump(obj, file, protocol=None, *, fix_imports=True, buffer_callback=None)
:
- 作用:将一个对象序列化并写入文件。
- 使用场景:通常用于将对象保存到文件,以便稍后再读取和使用。
- 参数
file
是文件对象,用于写入序列化的数据。 - 无返回值,数据被写入到文件中。
选择使用哪个函数取决于你的具体需求和场景。
pickle.dumps
主要用于在内存中进行对象序列化,返回字节对象。
pickle.dump
主要用于将序列化后的数据写入文件,存储到磁盘。
反序列化(Deserialization)pickle.loads
方法
反序列化是将字节流或其他格式还原为原始数据结构的过程。
pickle.loads
主要对应pickle.dumps
。用于在内存中进行序列化和反序列化,分别将对象转换为字节对象和将字节对象还原为对象。
pickle.loads(bytes_object, *, fix_imports=True, encoding="ASCII", errors="strict", buffers=None)
:
loads
是load string
的缩写,用于将字符串(字节流)反序列化为对象。- 参数
bytes_object
是要反序列化的字节对象。 - 返回值是反序列化后的对象。
反序列化(Deserialization)pickle.load
方法
pickle.load
主要对应pickle.dump
。用于与文件之间进行序列化和反序列化,分别将对象写入文件和从文件中读取序列化的数据并还原为对象。
pickle.load(file, *, fix_imports=True, encoding="ASCII", errors="strict", buffers=None)
:
load
是load from file
的缩写,用于从文件中读取序列化的数据并反序列化为对象。- 参数
file
是文件对象。 - 返回值是反序列化后的对象。
案例1:网络传输
pickle.dumps()
将列表序列化为字节流,才可以进行网络传输(因为网络底层只认识字节)
import pickle
dic = {"name": "admin", "password": 123}
bs = pickle.dumps(dic)
print(bs)
#运行结果
b'\x80\x04\x95!\x00\x00\x00\x00\x00\x00\x00}\x94(\x8c\x04name\x94\x8c\x05admin\x94\x8c\x08password\x94K{u.'
pickle.loads()
将网络传输过来的字节,重新还原回原始的数据结构。
bs= b'\x80\x04\x95!\x00\x00\x00\x00\x00\x00\x00}\x94(\x8c\x04name\x94\x8c\x05admin\x94\x8c\x08password\x94K{u.'
dic = pickle.loads(bs)
print(dic, type(dic))
#运行结果
{'name': 'admin', 'password': 123} <class 'dict'>
案例2:文件存储
pickle.dumps()
用于将字典 data
序列化为二进制字节流,并将其写入文件 'data.pkl'
。
import pickle
data = {'name': 'John', 'age': 30, 'city': 'New York'}
# 序列化
serialized_data = pickle.dumps(data)
with open('data.pkl', 'wb') as file:
file.write(serialized_data)
pickle.loads()
用于将字节流反序列化为原始的数据结构。
import pickle
# 从文件中读取序列化的数据
with open('data.pkl', 'rb') as file:
serialized_data = file.read()
# 反序列化
loaded_data = pickle.loads(serialized_data)
print(loaded_data)
需要注意的是,pickle
不是唯一的序列化方法。在实际应用中,你可能还会遇到其他格式,比如 JSON(使用 json
模块)、XML、或者 Protocol Buffers 等,取决于你的需求和使用场景。
反面案例3:
dic = {"name": "admin", "password": 123}
f = open("data.txt", mode="w", encoding="utf-8")
f.write(dic)
#运行结果
f.write(dic)
TypeError: write() argument must be str, not dict #write() 方法中传递的参数必须是字符串(str),而不能是字典(dict)
如果你强制转化成字符串去存储这个字典,str(dic)
虽然执行会成功
dic = {"name": "admin", "password": 123}
f = open("data.txt", mode="w", encoding="utf-8")
f.write(str(dic))
但是当你重新读取f.read()
文件的时候,读取出来的结果依旧是字符串(str),而不是字典(dict)
f = open("data.txt", mode="r", encoding="utf-8")
s = f.read()
print(s, type(s))
#运行结果,依旧是字符串类型
{'name': 'admin', 'password': 123} <class 'str'>
这样,你就不能像字典一样进行关键字取值、循环等操作。
为了解决这个问题,你还得使用eval()
进行特殊处理
f = open("data.txt", mode="r", encoding="utf-8")
s = f.read()
d = eval(s)
print(d, type(d))
#运行结果
{'name': 'admin', 'password': 123} <class 'dict'>
但是,使用 eval()
函数来解析字符串是一个潜在的安全风险,因为它可以执行任意的 Python 代码,可能导致代码注入或执行恶意代码的风险。强烈建议避免使用 eval()
来解析未知或不可信来源的数据。
在你的情况下,如果你知道文件中包含的是一个合法的字典表示形式,更安全的方法是使用 json
模块来加载 JSON 数据:
import json
with open("data.txt", mode="r", encoding="utf-8") as f:
json_str = f.read()
loaded_dict = json.loads(json_str)
print(loaded_dict, type(loaded_dict))
这样,你可以确保加载的数据是一个有效的 JSON 格式,而且不会执行任意的代码。
如果你依然需要处理 Python 字典表示形式而非 JSON,可以使用 ast.literal_eval()
而非 eval()
,因为 literal_eval()
更安全,只会解析字面常量,而不会执行任意代码。不过,使用 JSON 通常是更好的选择。
案例4:
把数据存储到文件中最合理的方案就是使用pickle.dump()
dic = {"name": "admin", "password": 123}
with open("data.txt", mode="wb") as f: # f = open("data.txt", mode="wb")
pickle.dump(dic, f)
序列化存储后的文件我们打开后看到的是这样的乱码
读取序列化的文件使用pickle.load()
with open("data.txt", mode="rb") as f: # f = open("data.txt", mode="rb")
dic = pickle.load(f)
print(dic, type(dic))
#执行结果
{'name': 'admin', 'password': 123} <class 'dict'>