概述
Python中提供了三个用于序列化和反序列化的模块:marshal、json和pickle,这里对pickle模块进行总结归纳。
pickle是Python中的一个标准模块,其实现了序列化和反序列化的二进制协议,可以对对象进行序列化和反序列化操作,“Pickling”表示Python对象转换为字节流的过程,这一过程为序列化过程,“Unpickling”和“Pickling”恰好相反,是将字节流转换为Python对象的过程,这一过程也称为反序列化。,但是其缺点是没有加密机制和数字签名,因此安全性差,尽管如此,pickle还是用于处理ad-hoc的理想模式。
优点
- 使用pickle可以对各种可以pickle的类型进行快速的压缩
缺点
- 没有安全机制(没有加密机制和数字签名),因此不能对不可信的或为授权的字节流进行反序列化
pickle和json区别
- 1.json是一种文本序列化格式(它输出unicode文本,虽然大多数时候它被编码为utf-8),而pickle是一种二进制序列化格式;
- 2.json序列化后的文件具有可读性,而pickle不具有;
- 3.json广泛用于其他语言汇总,pickle是Python特有的;
- 4.默认情况下,JSON只能用于Python内置类型的一个子集,并且不包含自定义类; pickle可以用于大量的Python类型。
pickle API
属性
pickle.HIGHEST_PROTOCOL
:表示最高可用的pickle协议,在dump()
方法和load()
方法中作为参数使用,也可以使用在Pickle构造方法中。
pickle.DEFAULT_PROTOCOL
:表示默认的pickle协议。
方法
pickle.dump(obj, file, protocol=None, *, fix_imports=True)
:将pickled的对象写入二进制文件中,和Pickler(file, protocol).dump(obj)
方法等价。
pickle.dumps(obj, protocol=None, *, fix_imports=True)
:将pickled的对象序列化后返回一个byte对象,而不是写入到文件中。
pickle.load(file, *, fix_imports=True, encoding="ASCII", errors="strict")
:从打开的二进制文件中中读取一个pickle对象,并返回该对象的重组对象,和Pickler(file).load(obj)
方法等价;
pickle.loads(bytes_object, *, fix_imports=True, encoding="ASCII", errors="strict")
:从字节流中读取一个pickle对象表示并返回该对象的重组对象;
异常
exception pickle.PickleError
:pickling和unpickling时的公共异常类,继承自Exception;
exception pickle.PicklingError
:序列化一个unpickabled对象时将抛出,继承自PicklerError;
exception pickle.UnpicklingError
:反序列化一个unpickabled对象时将抛出,继承自PicklerError;
类
class pickle.Pickler(file, protocol=None, *, fix_imports=True)
:将pickled数据流写入二进制文件中;
class pickle.Unpickler(file, *, fix_imports=True, encoding="ASCII", errors="strict")
:从二进制文件中读取pickled数据流。
哪些类型可以picked和unpicked
可以picked的类型:
- None, True, and False
- integers, floating point numbers, complex numbers
- strings, bytes, bytearrays
- 仅限于包含pickable对象的tuples, lists, sets, dictionaries
- 在模块顶层定义的函数 (使用 def, lambda函数不行)
- 在模块顶层定义的内置函数
- 在模块顶层定义的类
- 类的
__dict__
或调用__getstate __()
的结果的实例。
1.对函数而言,是通过函数名来pickle的,只有函数名时可pickled的,函数代码、属性都不是可pickled的,因此,如果需要序列化函数或方法,必须导入对应方法所在的模块和对象名。
2.类也通过类名来进行pickle的,所有的类代码和属性都不是可pickled的。
示例
下面对基于上篇文章struct模块处理二进制文件时定义的类Student简单做了修改,通过pickle对其进行序列化和反序列化,代码如下:
import sys
import os
import pickle
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
@property
def age(self):
return self.__age
@age.setter
def age(self, age):
assert isinstance(age, int), "age must be integer"
self.__age = age
def export_binary(self,filename):
fh = None
try:
fh = open(filename, "wb")
pickle.dump(self, fh, pickle.HIGHEST_PROTOCOL)
return True
except(EnvironmentError, pickle.PicklingError) as err:
print("{0}: export err:{1}".format(
os.path.basename(sys.argv[0]), err
))
return False
finally:
if fh is not None:
fh.close()
def import_binary(self, filename):
fh = None
try:
fh = open(filename, "rb")
s = pickle.load(fh)
print(s.name, s.age) # zhangsan 21
return True
except(EnvironmentError,pickle.UnpicklingError) as err:
print("{0}: export err:{1}".format(
os.path.basename(sys.argv[0]), err
))
return False
finally:
if fh is not None:
fh.close()
if __name__ == "__main__":
s1 = Student("zhangsan", 21)
s2 = Student("Lisi", 23)
s1.export_binary("s1.bin")
s1.import_binary("s1.bin")
总结
pickle模块还是比较复杂的,这里仅仅总结了部分内容,以后对剩余内容再进行总结。
参考文档:https://docs.python.org/3/library/pickle.html