本文约2180字,建议阅读时间12~15分钟
关键字:python,序列化,反序列化,字节编码,pickle
pickle模块主要用于将python对象与二进制序列之间的转换,是python所特有的,pickle模块是不安全的,只有当把字节序列转换为python对象时才是可信的,当操作不可信的数据时,建议使用json格式。pickle模块会追踪已经被序列化对象的位置,所以随后对相同对象的引用将不再被序列化。
目前存在6种不同的pickle协议,通常越高的python版本可以使用更高级的协议。
版本 | 特征 |
version 0 | 人类可读,与较早版本的python兼容 |
version 1 | 旧式二进制形式,与较早版本的python兼容 |
version 2 | python2.3引入,提供更有效的pickle类型 |
version 3 | python3.0新增,支持bytes对象,不能被python2反pickle |
version 4 | python3.4新增,支持超大对象及更多类型的对象 |
version 5 | python3.8新增,支持带外数据,加速带内数据 |
将python对象序列化,可使用dumps函数,相反可使用loads函数。通常创建Pickler和Unpickler对象可以更多地对序列化与反序列化进行控制。
1、相关常数
(1)pickle.HIGHEST_PROTOCOL
最高pickle协议版本号(整数),可以作为dumps、loads函数以及Pickler构造函数的protocol参数的值。
(2)pickle.DEFUALT_PROTOCOL
pickle的默认协议版本号(整数),当前默认值为4,可能小于HIGHEST_PROTOCOL.
2、相关函数
(1)将python对象写入pickle文件
pickle.dump(obj,file,protocol=None,*)
#obj为python对象,file为pickle文件
#等同于Pickler(file,protocol).dump(obj)
import pickle as pk
data='This is the corpus of family name.'
with open('data.pickle','wb') as f:
pk.dump(data,f,pk.HIGHEST_PROTOCOL)
#在本地生成data.pickle文件
#注:二进制写为’wb’
(2)将python对象转换为bytes对象
pickle.dumps(obj,protocol=None,*)
pk.dumps('abc')
#返回b'\x80\x04\x95\x07\x00\x00\x00\x00\x00\x00\x00\x8c\x03abc\x94.'
(3)读取pickle文件
pickle.load(file,*)
#file为pickle文件
#其他主要参数encoding默认为’ASCII’,errors默认为’strict’
#等同于Unpickler(file).load()
with open('data.pickle','rb') as f:
data=pk.load(f)
print(data)
返回:
'This is the corpus of family name.'
(4)将类bytes对象转换为python对象
pickle.loads(obj_b,*)
#obj_b为类bytes对象
pk.loads(pk.dumps('abc'))
#返回’abc’
3、相关异常
pickle.PickleError
#继承自Exception
pickle.PicklingError
#继承自PickleError
pickle.UnpicklingError
#继承自PickleError
4、相关类
(1)Pickler
创建Pickler对象(写入器)
pickler=pickle.Pickler(file,protocol=None,*)
数据写入
pickler.dump(obj)
#obj为python对象
持久化
pickler.persistent_id(obj)
默认情况下什么都不做,如果返回None,obj将被正常序列化,如果返回其他值,pickler对象将把其作为obj的持久化 ID。持久化ID是Unpickler.persistent_load()定义的。
分发表
pickler.dispatch_table
分发表是可以通过copyreg.pickle()函数声明的压缩注册表,它是键为类、值为压缩函数的映射。一个压缩函数只有与类相关的单参数并且应该遵循同样的接口作为__reduce__()方法。
压缩重载
reducer_override(self,obj)
在pickler子类中可定义的特殊压缩器,在dispatch_table中该方法生成的压缩器比其他压缩器具有优先级,python3.8新增。
快速转换模式
pickler.fast
不推荐使用,当被设置真实值时能够快速转换。
(2)Unpickler
创建Unpickler对象(读取器)
unpickler=pickle.Unpickler(file,*)
#还可以设置主要参数encoding=’ASCII’,errors=’strict’
数据读取
unpickler.load()
持久化
unpickler.persistent_load(pid)
默认抛出UnpicklingError,如果定义了,将返回被持久化ID特殊化的对象,如果遇到非法的持久化ID,将抛出UnpicklingError。
导入模块的名称
unpickler.find_class(module,name)
module和name都为字符串,也可以用于发现模块中的函数。
(3)PickleBuffer
创建PickleBuffer对象
picklebuffer=PickleBuffer(buffer)
一个代表可pickle数据缓冲器的装饰器,buffer必须是一个buffer-providing对象,比如类字节对象或者n维数组。该对象只能采用协议5或者更高版本时才可序列化,它是python3.8新增的。
picklebuffer.raw()
返回buffer的内存查看对象memoryview
picklebuffer.release()
释放潜在的缓冲
5、可pickle和反pickle的对象
(1)None、True、False;
(2)整数、浮点数、复数;
(3)字符串、字节,字节组;
(4)元组、列表、集合、字典中仅包含可pickle的对象;
(5)定义在模块顶层的函数(如def定义的而非lambda定义的);
(6)定义在模块顶层的内建函数;
(7)定义在模块顶层的类;
(8)那些拥有__dict__或者调用__getstate__()的结果可pickle的类的实例;
当pickle函数或类时,只有函数或类的名称可被pickle。
6、pickle类的实例
默认情况下,pickle将通过内在机制回溯类和实例的属性,当一个类的实例不能被pickle时,它的__init__()方法将不被唤起,默认的行为是首先创建一个非初始化的实例,然后恢复已经保存的属性。当类提供了如下一种或多种特殊方法时将改变这种默认的行为:
(1)object.__getnewargs_ex__()
在协议2及以上的版本中,在反pickle时类通过执行该方法时能够控制传递给__new__()方法的值,该方法返回元组对(args,kwargs)。当类中的__new__()方法只需要关键字参数时应该执行该方法。
(2)object.__getnewargs__()
该方法与object.__getnewargs_ex__()具有相同的目的,只是该方法仅支持位置参数,且返回args的元组。如果object.__getnewargs_ex__()被定义了,则该方法将不能被调用。
(3)object.__getstate__()
如果类定义了该方法,调用时返回的对象被pickle成实例目录,而不是实例字典的目录。
(4)object.__setstate__(state)
如果定义了该方法,在反pickle状态时将被调用,此时没有必要将状态对象设成字典,否则在pickle状态时必须将字典的元素分配到新的实例字典中。
上述方法在pickle时并不会直接使用,事实上,这些方法是执行__reduce__()特殊方法的复制协议的一部分。在类中直接执行__reduce__()方法是易于出错的,因此应该使用诸如上述方法等高级接口。
(5)object.__reduce__()
该方法不带参数,通常返回元组,也可以是字符串。
(6)object.__reduce_ex__(protocol)
该方法需要一个整型参数,即协议版本号。
7、类型、函数和其他对象的自定义压缩
有时,分发表可能并不足够灵活,例如基于其他规则的自定义pickle而不是基于对象的类型,或者自定义函数和类的pickle,可以通过创建Pickler的子类和执行reducer_override()方法来实现,这种方法将返回一个随机的元组。如果dispatch_table和reducer_override()被同时定义,那么reducer_override()将拥有更高优先级。
(完)
欢迎关注【lambda派】!
相关阅读:
迭代器函数模块itertools
数理统计模块statistics
派生枚举类:IntEnum、IntFlag、Flag
数组二分插入:bisect
堆队列:heapq