Customize pickle behavior for backwards compatibility
Python's copy_reg
module allows to register custom reducers and constructors. Is it correct that I can only customize the unpickle behavior of objects that I serialized after I registered the custom serializer/unserializer via copy_reg.pickle
?
Example:
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)
It seems that copy_reg works by simply replacing the constructor function in the pickle format:
>>> print(legacy_c_ser)
'ccopy_regn_reconstructornp0n(c__main__nCnp1[...]'
>>> print(new_c_ser)
'c__main__nload_Cnp0[...]'
Is writing my own pickle.Unpickler
class the only way to customize the unpickle behavior of legacy pickle files? I dont want to do that since I rather use cPickle
than pickle
because of efficiency.
My problem is that I have pickled objects from a 3rd party library and the pickle format changed when I upgraded the library.
Pickle is supposed to be backward compatible across python releases (let's ignore python 2.x versus 3.x, for now). So when you say the pickling format changed, you mean the way that this 3rd party library registers their classes (or other objects) has changed, correct?
If that's the case… to make this work, you'd need to do some trickery. First you get the source for the old class definition, and when you grab the raw pickle you need to change the reference from the existing class to match the path to the code for the old version of the class. This should be in clear text (even in HIGHEST_PROTOCOL
), so it shouldn't be an issue to grab and edit that part of the pickle string. You then would be able to unpickle the old objects, but they'd be pointing to the old class definition. A "format converter" would be needed to convert the old objects you'd be unpicking to the new class instance objects -- basically create new class instances that take the relevant state from the old class instances.
上一篇: 酸洗和取消动态生成的类
下一篇: 自定义pickle行为以实现向后兼容