简体   繁体   中英

Python pickle instance variables

I am doing some calculations on an instance variable, and after that is done I want to pickle the class instance, such that I don't have to do the calculations again. Here an example:

import cPickle as pickle

class Test(object):
    def __init__(self, a, b):
        self.a = a
        self.b = b
        self.c = None
    def compute(self, x):
        print 'calculating c...'
        self.c = x * 2

test = Test(10, 'hello')
test.compute(6)

# I have computed c and I want to store it, so I don't have to recompute it again:

pickle.dump(test, open('test_file.pkl', 'wb'))

After test.compute(6) I can check to see what test.__dict__ is:

>>> test.__dict__
{'a': 10, 'c': 12, 'b': 'hello'}

I thought that is what going to get pickled; however,

When I go to load the class instance:

import cPickle as pickle

from pickle_class_object import Test

t2 = pickle.load(open('test_file.pkl', 'rb'))

I see this in the shell:

calculating c...

Which means that I did not pickle c and I am computing it over again.

Is there a way to pickle test how I want to? So I don't have to compute c over again. I see that I could just pickle test.__dict__ , but I am wondering if there is a better solutions. Also, my understanding about what is going on here is weak, so any comment about what is going would be great. I've read about __getstate__ and __setstate__ , but I don't see how to apply them here.

You are importing the pickle_class_object module again, and Python runs all code in that module.

Your top-level module code includes a call to .compute() , that is what is being called.

You may want to move the code that creates the pickle out of the module, or move it to a if __name__ == '__main__': guarded section:

if __name__ == '__main__':
    test = Test(10, 'hello')
    test.compute(6)

    pickle.dump(test, open('test_file.pkl', 'wb'))

Only when running a python file as the main script is __name__ set to __main__ ; when imported as a module __name__ is set to the module name instead and the if branch will not run.

Pickling works as you expect it to work. The problem here is when you run the new script, you import the module that contains the class Test . That entire module is run including the bit where you create test .

The typical way to handle this sort of thing would be to protect the stuff in a if __name__ == "__main__: block.

class Test(object):
    def __init__(self, a, b):
        self.a = a
        self.b = b
        self.c = None
    def compute(self, x):
        print 'calculating c...'
        self.c = x * 2

if __name__ == "__main__":
    import cPickle as pickle

    test = Test(10, 'hello')
    test.compute(6)

    # I have computed c and I want to store it, so I don't have to recompute it again:

    pickle.dump(test, open('test_file.pkl', 'wb'))

That isn't what's happening. You import a python module that has code in it at the top level, which executes when you import the module. You can see that your code works as you intended:

import cPickle as pickle

class Test(object):
    def __init__(self, a, b):
        self.a = a
        self.b = b
        self.c = None
    def compute(self, x):
        print 'calculating c...'
        self.c = x * 2

test = Test(10, 'hello')
test.compute(6)

pickle.dump(test, open('test_file.pkl', 'wb'))

t2 = pickle.load(open('test_file.pkl', 'rb'))
print t2.c


--output:--
calculating c...
12

If your code worked as you describe, then you would see "calculating c..." twice.

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