Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to unpickle a Python instance that was saved before the class changed a member variable to a property?

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)
like image 359
doetoe Avatar asked Jan 25 '26 07:01

doetoe


1 Answers

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.

like image 190
Peter Wood Avatar answered Jan 27 '26 22:01

Peter Wood



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!