Pickled 对象版本控制

发布于 2024-08-23 06:07:00 字数 345 浏览 8 评论 0原文

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

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

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

谢谢

I am working on a project where we have a large number of objects being serialized and stored to disk using pickle/cPickle.

As the life of the project progresses (after release to customers in the field) it is likely that future features/fixes will require us to change the signature of some of our persisted objects. This could be the addition of fields, removing of fields, or even just changing the invariants on a piece of data.

Is there a standard way to mark an object that will be pickled as having a certain version (like serialVersionUID in Java)? Basically, if I am restoring an instance of Foo version 234 but the current code is 236 I want to receive some notification on unpickle. Should I just go ahead and roll out my own solution (could be a PITA).

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

盛夏已如深秋| 2024-08-30 06:07:00

pickle 格式没有这样的限制。为什么不将“序列版本号”作为对象属性的一部分,与其他属性一起进行腌制呢?然后,通过比较实际版本和所需版本就可以轻松获得“通知”——不明白为什么它应该是 PITA。

The pickle format has no such proviso. Why don't you just make the "serial version number" part of the object's attributes, to be pickled right along with the rest? Then the "notification" can be trivially had by comparing actual and desired version -- don't see why it should be a PITA.

酒解孤独 2024-08-30 06:07:00

考虑 Tomasz Früboes 建议的以下类 mixin 此处

# 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 时由 pickle 调用,而 __setstate__ 在 unpickling 时由 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

Consider the following class mixin suggested by Tomasz Früboes here.

# 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_

The __getstate__ method is called by pickle upon pickling, and __setstate__ is called by pickle upon unpickling. This mix-in class can be used as a subclass of classes whose version you want to keep track of. This is to be used as follows:

# 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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文