Версирование маринованного объекта - PullRequest
4 голосов
/ 02 марта 2010

Я работаю над проектом, в котором у нас есть большое количество объектов, которые сериализуются и сохраняются на диск, используя pickle / cPickle.

По мере продвижения проекта (после выпуска для клиентов в полевых условиях), вероятно, что будущие функции / исправления потребуют от нас изменения подписи некоторых из наших постоянных объектов. Это может быть добавление полей, удаление полей или даже просто изменение инвариантов в части данных.

Существует ли стандартный способ пометить объект, который будет помечен как имеющий определенную версию (например, serialVersionUID в Java)? В основном, если я восстанавливаю экземпляр Foo версии 234, но текущий код - 236, я хочу получить уведомление об отмене выбора. Должен ли я просто пойти дальше и развернуть свое собственное решение (может быть, PITA).

Спасибо

Ответы [ 2 ]

4 голосов
/ 02 марта 2010

Формат pickle не имеет такой оговорки. Почему бы вам просто не сделать «серийный номер версии» частью атрибутов объекта, чтобы они были выбраны вместе с остальными? Тогда «уведомление» может быть тривиально получено путем сравнения фактической и желаемой версии - не понимаю, почему это должен быть PITA.

0 голосов
/ 22 августа 2018

Рассмотрим следующий классовый миксин, предложенный Томашем Фрюбо здесь .

# 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__ вызывается при травлении при травлении. Этот смешанный класс можно использовать в качестве подкласса классов, версию которых вы хотите отслеживать. Это должно использоваться следующим образом:

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