简体   繁体   中英

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

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 , eg 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

Sorry for the late response. Pickle flattens objects as dictionaries. This is how to fix it:

    def serialize(self, filename):
        """Simple object serialization given a filename"""
        with open(filename, 'wb') as f:
            pickle.dump(self.__dict__, 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.__dict__ = pickle.load(f)
            print("Deserialized value inside deserialize function: %d" % (self.x))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM