I have a class that used to have a field data, but later the class was changed and now data is a property.
I would like to be able to unpickle instances that were pickled before the change, to preserve backward compatibility. A minimal example for illustration (in Python 2, though it should be the same in Python 3):
import pickle
class X(object):
def __init__(self):
self.data = 100
pickle.dump(X(), open("x-file",'w'))
# Redefine the class
class X(object):
def __init__(self):
self._data = 101
@property
def data(self):
return self._data
y = pickle.load(open("x-file")) # cannot access the original data through y
print(y.data)
What I would like is to define a function load that unpickles the object, detects it is old style (e.g. by seeing that it doesn't have the _data field), and return a new style instance with its data instead. However, since the field data now is a property, the old data field was overwritten by the class definition.
Is there any easy way I can access the old data (i.e. other than parsing the pickle file myself, for example)?
EDIT After Peter Wood's answer, I got to this solution:
import pickle
class X(object):
def __init__(self):
self.data = 100
pickle.dump(X(), open("x-file",'w'))
# Redefine the class
class X(object):
def __init__(self):
self._data = 101
@property
def data(self):
return self._data
def __setstate__(self, state):
if not '_data' in state:
self._data = state['data']
del state['data']
self.__dict__.update(state)
y = pickle.load(open("x-file")) # cannot access the original data through y
print(y.data)
The documentation says in What can be pickled and unpickled?:
If you plan to have long-lived objects that will see many versions of a class, it may be worthwhile to put a version number in the objects so that suitable conversions can be made by the class’s
__setstate__()method.
This is one of four "magic" methods you can define on your classes to facilitate serialisation. See Pickling Class Instances.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With