Версирование маринованного объекта

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

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

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

Спасибо

2 ответа

Решение

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

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

# 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
Другие вопросы по тегам