Python的copy_reg
模块允许注册自定义Reducer和构造函数。是否正确我只能自定义之后序列化的对象的非线性行为我通过copy_reg.pickle
注册了自定义序列化器/反序列化器?
示例:
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_reg\n_reconstructor\np0\n(c__main__\nC\np1\[...]'
>>> print(new_c_ser)
'c__main__\nload_C\np0[...]'
编写我自己的pickle.Unpickler
类是自定义传统pickle文件的unpickle行为的唯一方法吗?我不想这样做,因为效率高于cPickle
而不是pickle
。
我的问题是我从第三方库中腌制了对象,并且在升级库时改变了pickle格式。
答案 0 :(得分:1)
Pickle应该在python版本中向后兼容(现在让我们忽略python 2.x与3.x)。因此,当您说酸洗格式发生变化时,您的意思是第三方库注册其类(或其他对象)的方式已更改,是否正确?
如果是这样的......要做到这一点,你需要做一些诡计。首先,您获得旧类定义的源代码,当您获取原始pickle时,您需要更改现有类的引用,以匹配旧版本类的代码路径。这应该是明文(即使在HIGHEST_PROTOCOL
),所以抓取和编辑pickle字符串的那一部分应该不是问题。然后你就可以解开旧对象,但是他们会指向旧的类定义。将您要取消的旧对象转换为新的类实例对象需要“格式转换器” - 基本上创建从旧类实例中获取相关状态的新类实例。