自定义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字符串的这部分应该不是问题。 然后,您可以取消旧对象的打开,但它们会指向旧的类定义。 需要一个“格式转换器”来将旧的对象转换为新的类实例对象 - 基本上创建新的类实例,它们从旧的类实例中获取相关状态。

链接地址: http://www.djcxy.com/p/64827.html

上一篇: Customize pickle behavior for backwards compatibility

下一篇: UnpicklingError: NEWOBJ class argument isn't a type object