Use pickle to load a state for class
我想用泡菜把脚弄湿,所以我写了一个这样的示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | class start(tk.Frame): def __init__(self,*args,**kwargs): tk.Frame.__init__(self,*args,**kwargs) frame = tk.Frame(self,width=600,height=600) self.val = 0 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.__dict__ = pickle.load(open("testtesttest.p","rb" )) def plus(self): self.val += 1 self.valLabel.config(text="%d"%(self.val)) def save(self): pickle.dump(self.__getstate__, open("testtesttest.p","wb" )) def __getstate__(self): return self.__getstate__ if __name__=='__main__': root = tk.Tk() start(root).pack() root.mainloop() |
所以这个应用程序的目标是一旦我点击了plus按钮,屏幕上就会有一个越来越多的数字。如果我保存它,关闭窗口,重新打开它,点击加载按钮,我将看到最后一次增加到的数字。我对pickle非常陌生,当前的代码会将这一点反馈给我:
1 2 3 4 5 6 | Exception in Tkinter callback Traceback (most recent call last): File"/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/tkinter/__init__.py", line 1550, in __call__return self.func(*args) File"/Users/caoanjie/pickleDemotry.py", line 18, in load self.__dict__ = pickle.load(open("testtesttest.p","rb" ))pickle. UnpicklingError: state is not a dictionary |
号
我想知道这里有什么问题。此外,我在网上看到了很多教程或示例代码,它们的功能如下:
1 2 | with open('save_game.dat', 'wb') as f: player= pickle.load |
您的问题可以简化为一个完全不使用tkinter的小类:
1 2 3 4 5 6 7 8 9 10 | >>> 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 |
您正在清除
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.
号
当您取消选择时,pickle会创建一个新的
相反,您应该将要保存和恢复的数据与恰好用于与用户交互的tkinter对象分开。这是一个常见的编程规则:将数据与表示分离。这里,我有一个保存数据的类,我可以将它与Tkinter类分开保存和恢复。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | 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() |
号