Versione di oggetto sottaceto
-
23-09-2019 - |
Domanda
Sto lavorando a un progetto in cui abbiamo un gran numero di oggetti che vengono serializzati e conservati sul disco utilizzando pickle
/cPickle
.
Man mano che la vita del progetto avanza (dopo il rilascio ai clienti sul campo), è probabile che le caratteristiche/correzioni future ci richiederanno di cambiare la firma di alcuni dei nostri oggetti persistiti. Questa potrebbe essere l'aggiunta di campi, la rimozione di campi o anche solo cambiare gli invarianti su un dato.
Esiste un modo standard per contrassegnare un oggetto che sarà sottaceto come una determinata versione (come serialVersionUID
in java)? Fondamentalmente, se sto ripristinando un'istanza di Foo versione 234 ma il codice corrente è 236, voglio ricevere una notifica su difetto. Dovrei semplicemente andare avanti e lanciare la mia soluzione (potrebbe essere una pita).
Grazie
Soluzione
Il pickle
Il formato non ha tale condizione. Perché non fai semplicemente la parte "Numero di versione seriale" degli attributi dell'oggetto, per essere in salamoia insieme al resto? Quindi la "notifica" può essere banale confrontando la versione effettiva e desiderata - non capire perché dovrebbe essere una pita.
Altri suggerimenti
Considera il seguente mixin di classe suggerito da Tomasz Früboes qui.
# 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_
Il __getstate__
Il metodo è chiamato da pickle
al decapaggio e __setstate__
è chiamato da sottaceto su uno stanco. Questa classe mix-in può essere utilizzata come sottoclasse di classi di cui si desidera tenere traccia. Questo deve essere usato come segue:
# 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