[关闭]
@spiritnotes 2016-07-23T14:56:53.000000Z 字数 1513 阅读 2420

Python中的序列化 pickle

Python DOING


pickle

Python有对应的序列化模块pickle和cplikle,pickle和cpickle一样,不同点在于前者使用python实现而后者使用c实现,表现为性能上的差别。主要功能就是使用了一种算法,将python对象转化成一系列字节,该过程调用serializing对象。生成的字符串可以再进行传输或者存储,而重构后可以创建一个拥有相同特征(the same charracteristics)的新的对象。

基本使用

直接导入该模块即可使用,在正常情况下,优先导入cpickle模块,如果出现异常再导入pickle模块。

  1. try:
  2. import cplickle as pickle
  3. except:
  4. import pickle

导出使用dump和dumps,参数有模式选择,模式0和1为二进制模式,模式2为ascii字符串模式,在性能(存储空间大小和编码解码时间)上有差异。dump作用在流上,而dumps作用在字符串上。
导入使用loads和load,导入的对象和原对象一样,但非同一个对象,其内存地址会发生变化。
可以通过使用os.fork和os.pipe创建进程间通信而直接传送对象。

dump了什么?

pickle函数主要是对实例对象(instance)的属性进行序列化,可以理解为是通过self.xxx进行赋值而产生的实例对象,而类变量、类中定义的函数等是通过代码执行产生的,这也是unpickle必须要有类定义的原因。

load的流程

load的流程主要由如下几个部分组成:

  1. 在域中查找pickled对象对应的class对象,如果未找到,则抛出异常;
  2. 调用该class的__new__,为对象分配内存;
  3. 调用其unpickle函数,跳过__init__函数直接生成对象;

getstate和setstate

当对象的数据类型不能被pickle时(套接字、文件句柄、数据库链接等),可以使用__getstate__和__setstate__来返回状态的一个子集,针对该子集进行pickle。新式类可以定义__getnewargs__,该函数应当返回被传递至类内存分配器(.__new__)。

环形引用

pickle协议能够自动处理对象间的环形引用。因此使用时不需要考虑该种情况。

相关问题

instancemethod

当使用python2.7进行pickle时如果有对象属性为函数对象,则可能会出现以下错误:

  1. PicklingError: Can't pickle <type 'instancemethod'>: attribute lookup __builtin__.instancemethod failed

该问题是由于其不支持序列化函数,可以使用copy_reg将MethodType注册为可序列化来解决

  1. import copy_reg
  2. import types
  3. def _pickle_method(m):
  4. if m.im_self is None:
  5. return getattr, (m.im_class, m.im_func.func_name)
  6. else:
  7. return getattr, (m.im_self, m.im_func.func_name)
  8. copy_reg.pickle(types.MethodType, _pickle_method)

更多方法可以见 https://blog.tankywoo.com/2015/09/06/cant-pickle-instancemethod.html

大对象问题

当文件超过一定的大小后,在pickle的时候会出错,主要有如下两种错误,除了手动将对象拆分后进行多次pickle,暂时还未发现解决办法。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注