自定义pickle行为以实现向后兼容
Python的copy_reg
模块允许注册自定义的reducer和构造函数。 是否正确,我只能自定义通过copy_reg.pickle
注册自定义序列化程序/非序列化程序后序列化的对象的unpickle行为?
例:
import pickle, copy_reg
class C(object):
pass
legacy_c_ser = pickle.dumps(C())
def reduce_C(obj):
print('reduce_C called')
tpl = obj.__reduce__()
tpl = (load_C, ) + tpl[1:]
return tpl
def load_C(*tpl):
print('load_C called')
return C()
copy_reg.constructor(load_C)
copy_reg.pickle(C, reduce_C, load_C)
new_c_ser = pickle.dumps(C())
# load_C is called
pickle.loads(new_c_ser)
# load_C is not called
pickle.loads(legacy_c_ser)
似乎copy_reg的工作原理是简单地用pickle格式替换构造函数:
>>> print(legacy_c_ser)
'ccopy_regn_reconstructornp0n(c__main__nCnp1[...]'
>>> print(new_c_ser)
'c__main__nload_Cnp0[...]'
正在编写我自己的pickle.Unpickler
类是定制传统pickle文件的unpickle行为的唯一方法吗? 我不想这样做,因为我宁愿使用cPickle
而不是因为效率而pickle
。
我的问题是,我已从第三方库中腌渍对象,并且在升级库时更改了pickle格式。
Pickle应该在Python版本之间向后兼容(现在让我们忽略python 2.x和3.x)。 所以当你说酸洗的格式改变时,你的意思是这个第三方库注册他们的类(或其他对象)的方式已经改变了,对吗?
如果是这种情况...为了使这项工作,你需要做一些欺骗。 首先获得旧类定义的源代码,并且当您抓取原始pickle时,您需要更改现有类的引用以将路径与旧版本类的代码相匹配。 这应该是明文形式(即使在HIGHEST_PROTOCOL
),所以抓取和编辑pickle字符串的这部分应该不是问题。 然后,您可以取消旧对象的打开,但它们会指向旧的类定义。 需要一个“格式转换器”来将旧的对象转换为新的类实例对象 - 基本上创建新的类实例,它们从旧的类实例中获取相关状态。
上一篇: Customize pickle behavior for backwards compatibility
下一篇: UnpicklingError: NEWOBJ class argument isn't a type object