腌制对象版本控制

时间:2010-03-02 05:45:34

标签: python serialization pickle serialversionuid

我正在开发一个项目,我们使用pickle / cPickle将大量对象序列化并存储到磁盘。

随着项目的生命周期的进展(在向现场客户发布之后),未来的功能/修复可能需要我们更改某些持久对象的签名。这可能是添加字段,删除字段,甚至只是更改一段数据的不变量。

是否有一种标准方法可以将一个被腌制的对象标记为具有某个版本(如Java中的serialVersionUID)?基本上,如果我正在恢复Foo版本234的实例,但当前代码是236我想收到关于unpickle的一些通知。我应该继续推出自己的解决方案(可能是PITA)。

由于

2 个答案:

答案 0 :(得分:4)

pickle格式没有这样的附带条件。为什么不将“序列版本号”作为对象属性的一部分,与其余属性一起腌制?然后通过比较实际版本和期望版本可以轻而易举地获得“通知” - 不明白为什么它应该是PITA。

答案 1 :(得分:0)

请考虑以下TomaszFrüboeshere建议的类混合。

# versionable.py
class Versionable(object):
    def __getstate__(self):
        if not hasattr(self, "_class_version"):
            raise Exception("Your class must define _class_version class variable")
        return dict(_class_version=self._class_version, **self.__dict__)
    def __setstate__(self, dict_):
        version_present_in_pickle = dict_.pop("_class_version")
        if version_present_in_pickle != self._class_version:
            raise Exception("Class versions differ: in pickle file: {}, "
                            "in current class definition: {}"
                            .format(version_present_in_pickle,
                                    self._class_version))
        self.__dict__ = dict_

__getstate__在酸洗时由pickle调用,而__setstate__在酸洗时由pickle调用。此混合类可用作您要跟踪其版本的类的子类。它的用法如下:

# bla.py
from versionable import Versionable
import pickle

class TestVersioning(Versionable):
    _class_version = 1

t1 = TestVersioning()

t_pickle_str = pickle.dumps(t1)

class TestVersioning(Versionable):
    _class_version = 2

t2 = pickle.loads(t_pickle_str) # Throws exception about wrong class version