对象版本化的序列化
我正在做一个项目,这个项目需要把很多对象进行序列化,然后存储到硬盘上,使用的是 pickle
或者 cPickle
。
随着项目的进展(在客户使用后),将来可能会需要对一些已经保存的对象进行修改,比如添加字段、删除字段,或者只是改变某些数据的规则。
有没有什么标准的方法可以标记一个将要被序列化的对象,让它有一个特定的版本号(就像Java中的 serialVersionUID
)?简单来说,如果我正在恢复一个版本为234的Foo对象,但当前代码是236,我希望在反序列化的时候能收到一些通知。我是不是应该自己想个办法来解决这个问题(这可能会很麻烦)。
谢谢
2 个回答
6
考虑一下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
调用,而__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
7
pickle
格式没有这样的限制。为什么不把“序列版本号”作为对象的属性之一,这样在进行序列化时就可以和其他内容一起保存呢?这样一来,通过比较实际版本和期望版本,就能轻松得到“通知”——我不明白为什么这会变得这么麻烦。