Search code examples
pythondeserializationself

Self unpickling in class method in python


I am trying to create an object which can serialize and deserialize itself with a class method, without using the return statement (I do not want a static method). This is a concept of my class and a naive use case:

import pickle

class A:
    def __init__(self):
        self.x = 0

    def add(self):
        self.x += 1

    def serialize(self, filename):
        """Simple object serialization given a filename"""
        with open(filename, 'wb') as f:
            pickle.dump(self, f)
            print("Serialized with value of: %d" % (self.x))

    def deserialize(self, filename):
        """Simple object deserialization given a filename"""
        with open(filename, 'rb') as f:
            print("self.x before load (inside deserialize): %d" % (self.x))
            self = pickle.load(f)
            print("Deserialized value inside deserialize function: %d" % (self.x))



a1 = A()
a2 = A()

a1.add()
a1.add()

a1.serialize('a.pkl')
a2.deserialize('a.pkl')

print("Deserialized value outside: %d" % (a2.x))

However, once I leave the deserialization method, self (in this case, the instance a2) does not keep its value.

Output when run:

>> Serialized with value of: 2
>> self.x before load (inside deserialize): 0
>> Deserialized value inside deserialize function: 2
>> Deserialized value outside: 0

Why is this happening? I have also tried with deepcopy just after the pickle.load in the function deserialize but nothing seems to work, and I would like to understand why.

Thanks in advance


Solution

  • The reason this doesn't work is that because you can't assign to self (or rather: doing that doesn't do what you think it does). If you're interested to find out what actually happens, try assigning something weird to self, e.g. self = "foobar" (the behaviour will be unchanged).


    Make deserialize a classmethod and use it as a "constructor":

    @classmethod
    def deserialize(cls, filename):
        """Simple object deserialization given a filename"""
        with open(filename, 'rb') as f:
            obj = pickle.load(f)
            print("Deserialized value inside deserialize function: %d" % (obj.x))
            return obj
    

    Then use it like this:

    a2 = A.deserialize('a.pkl')
    

    Output:

    Serialized with value of: 2
    Deserialized value inside deserialize function: 2
    Deserialized value outside: 2