I want my class to implement Save and Load functions which simply do a pickle of the class. But apparently you cannot use ‘self’ in the fashion below. How can you do this?
self = cPickle.load(f) cPickle.dump(self,f,2)
There is an example of how to pickle an instance here, in the docs. (Search down for the “TextReader” example). The idea is to define
__setstate__ methods, which allow you to define what data needs to be pickled, and how to use that data to re-instantiate the object.
The dump part should work as you suggested. for the loading part, you can define a @classmethod that loads an instance from a given file and returns it.
@classmethod def loader(cls,f): return cPickle.load(f)
then the caller would do something like:
class_instance = ClassName.loader(f)
This is what I ended up doing. Updating the
__dict__ means we keep any new member variables I add to the class and just update the ones that were there when the object was last pickle’d. It seems the simplest while maintaining the saving and loading code inside the class itself so calling code just does an object.save().
def load(self): f = open(self.filename, 'rb') tmp_dict = cPickle.load(f) f.close() self.__dict__.update(tmp_dict) def save(self): f = open(self.filename, 'wb') cPickle.dump(self.__dict__, f, 2) f.close()
If you want to have your class update itself from a saved pickle… you pretty much have to use
__dict__.update, as you have in your own answer. It’s kind of like a cat chasing it’s tail, however… as you are asking the instance to essentially “reset” itself with prior state.
There’s a slight tweak to your answer. You can actually pickle
>>> import dill >>> class Thing(object): ... def save(self): ... return dill.dumps(self) ... def load(self, obj): ... self.__dict__.update(dill.loads(obj).__dict__) ... >>> t = Thing() >>> t.x = 1 >>> _t = t.save() >>> t.x = 2 >>> t.x 2 >>> t.load(_t) >>> t.x 1
dumps instead of
dump because I wanted the pickle to save to a string. Using
dump to a file also works.
And, actually, I can use
dill to pickle an class instance to a file, for later use… even if the class is defined interactively. Continuing from above…
>>> with open('self.pik', 'w') as f: ... dill.dump(t, f) ... >>>
then stopping and restarting…
Python 2.7.10 (default, May 25 2015, 13:16:30) [GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import dill >>> with open('self.pik', 'r') as f: ... t = dill.load(f) ... >>> t.x 1 >>> print dill.source.getsource(t.__class__) class Thing(object): def save(self): return dill.dumps(self) def load(self, obj): self.__dict__.update(dill.loads(obj).__dict__) >>>
dill, which is available here: https://github.com/uqfoundation
This is how I did it. The advantage is that you do not need to create a new object. You can just load it directly.
def save(self): with open(self.filename, 'wb') as f: pickle.dump(self, f) @classmethod def load(cls, filename): with open(filename, 'rb') as f: return pickle.load(f)
How to use it:
class_object.save() filename = class_object.filename del class_object class_object = ClassName.load(filename)
Bellow, I updated the answer with a fully working minimal example. This can be adapted to your own needs.
import pickle class Test: def __init__(self, something, filename) -> None: self.something = something self.filename = filename def do_something(self) -> None: print(id(self)) print(self.something) def save(self): with open(self.filename, 'wb') as f: pickle.dump(self, f) @classmethod def load(cls, filename): with open(filename, 'rb') as f: return pickle.load(f) test_object = Test(44, "test.pkl") test_object.do_something() test_object.save() filename = test_object.filename del test_object recovered_object = Test.load(filename) recovered_object.do_something()