Use Pickle To Load A State For Class
Solution 1:
Your problem can be simplified to a small class that doesn't use tkinter at all:
>>> class Foo:
... def __getstate__(self):
... print('getstate')
... return self.__getstate__
...
>>> obj = pickle.loads(pickle.dumps(Foo().__getstate__))
getstate
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
_pickle.UnpicklingError: state is not a dictionary
You are pickling the __getstate__
instance method, not the full state of the start
class. Python lets you do that, assuming that you also implement a __setstate__
method that knows how to rebuild an object from that information. From the docs:
Upon unpickling, if the class defines __setstate__(), it is called with the unpickled state. In that case, there is no requirement for the state object to be a dictionary. Otherwise, the pickled state must be a dictionary and its items are assigned to the new instance’s dictionary.
When you unpickle, pickle creates a new instance of state
but since the class has no __setstate__
method, pickle tries to restore the object's __dict__
. That fails because the unpickled object is an instance method, not a dict
. And this shows a bigger problem with your approach.
pickle
recreates entire objects, it doesn't restore into existing objects. In your case, if you pickled the entire start
object, it would restore a second start
object in addition to the one you created yourself. You could assign that object's __dict__
to your __dict__
, but that is a very risky proposition. You would loose the entire state of your Frame object in favor of what happened to be in the object you pickled. Its likely impossible to pickle the entire object anyway because tkinter is a C extension module.
Instead, you should separate the data you want to save and restore from the tkinter object you happen to use to interact with the user. This is a common programming rule: separate data from presentation. Here, I have a class holding data and I can save and restore it separate from the tkinter class.
import tkinter as tk
import pickle
class State:
def __init__(self):
self.val = 0
class start(tk.Frame):
def __init__(self,*args,**kwargs):
tk.Frame.__init__(self,*args,**kwargs)
frame = tk.Frame(self,width=600,height=600)
self.state = State()
self.plusButton = tk.Button(self,text="plus",command=self.plus)
self.plusButton.pack()
self.valLabel = tk.Label(self)
self.valLabel.pack()
self.saveButton = tk.Button(self,text="save",command=self.save)
self.saveButton.pack()
self.loadButton = tk.Button(self,text="load",command=self.load)
self.loadButton.pack()
def load(self):
self.state = pickle.load(open( "testtesttest.p", "rb" ))
self.valLabel.config(text="%d"%(self.state.val))
def plus(self):
self.state.val += 1
self.valLabel.config(text="%d"%(self.state.val))
def save(self):
pickle.dump(self.state, open( "testtesttest.p", "wb" ), 4)
if __name__=='__main__':
root = tk.Tk()
start(root).pack()
root.mainloop()
Post a Comment for "Use Pickle To Load A State For Class"