Eingelegtes Objektversioning
-
23-09-2019 - |
Frage
Ich arbeite an einem Projekt, bei dem eine große Anzahl von Objekten serialisiert und auf der Festplatte gespeichert wird pickle
/cPickle
.
Mit der Lebensdauer des Projekts (nach der Veröffentlichung an Kunden vor Ort) ist es wahrscheinlich, dass zukünftige Funktionen/Korrekturen die Signatur einiger unserer anhaltenden Objekte ändern müssen. Dies kann die Hinzufügung von Feldern, das Entfernen von Feldern oder die Änderung der Invarianten auf einem Datenstück sein.
Gibt es eine Standardmethode, um ein Objekt zu markieren, das als eine bestimmte Version eingelegt wird (wie serialVersionUID
in Java)? Wenn ich eine Instanz von Foo Version 234 wiederherstellt, aber der aktuelle Code 236 ist, möchte ich eine Benachrichtigung über Unpickle erhalten. Sollte ich einfach meine eigene Lösung ausrollen (könnte eine Pita sein).
Vielen Dank
Lösung
Das pickle
Das Format hat keine solche Voraussetzungen. Warum machen Sie nicht einfach die "serielle Versionsnummer" Teil der Attribute des Objekts, um gleich mit dem Rest eingelegt zu werden? Dann kann die "Benachrichtigung" durch Vergleich der tatsächlichen und gewünschten Version trivial gehabt werden - sehen Sie nicht, warum es sich um eine Pita handeln sollte.
Andere Tipps
Betrachten Sie den folgenden Klassenmixin, der von Tomasz Früches vorgeschlagen wurde hier.
# 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_
Das __getstate__
Methode wird aufgerufen von pickle
beim Einweichen und __setstate__
wird durch Gurke beim Unpacken genannt. Diese Mix-In-Klasse kann als Unterklasse von Klassen verwendet werden, deren Version Sie im Auge behalten möchten. Dies ist wie folgt zu verwenden:
# 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