Pickle不适用于tkinter

时间:2016-10-25 15:59:46

标签: python tkinter pickle

我正在与Tkinter进行一场小游戏,它有一个使用pickle的保存功能。但是,当我尝试保存时,它会抛出以下消息;

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Python34\lib\tkinter\__init__.py", line 1533, in __call__
    return self.func(*args)
  File "C:\Users\Benedict\Documents\Python\Migrant Simulator\MigSim 2016.10\migrant-stimulator.py", line 260, in save
    pickle.dump(self.game,file)
_pickle.PicklingError: Can't pickle <class 'tkapp'>: attribute lookup tkapp on __main__ failed

问题是,我试图腌制的数据不包含与Tkinter相关的数据,所以我不明白为什么它说<class 'tkapp'>
以下是相关代码位的摘要:

...
class Game(object):

    def __init__(self,name,nodes={},start=None,history=[]):
        self.name=name
        self.nodes=nodes
        self.start=start
        self.history=history

class App:

    def __init__(self, master):
        self.master=master
...
    def save(self):
        if self.file_name==None:
            self.save_as()
        file=open(self.file_name,'wb')
        pickle.dump(self.game,file) # self.game is an instance of the Game class defined elsewhere
        print(str(type(self.game)))
        file.close()

    def save_as(self):
        self.file_name=filedialog.asksaveasfilename()
        self.save()
...
root = Tk()

app = App(root)

root.mainloop()

我该如何解决这个问题?我已按照相关问题的建议尝试更改__getstate__,但它没有用。

编辑:没关系,事实证明,在我的数据结构中,我留下了一个BooleanVar。

2 个答案:

答案 0 :(得分:2)

简短的回答是,你不能腌制与tkinter相关的任何东西。原因是tkinter应用程序使用嵌入式Tcl解释器来维护内存中GUI的状态,而Tcl对python pickle格式一无所知(同样,pickle对tcl解释器一无所知)。根本无法保存和恢复由Tcl解释器管理的数据。

您必须将要保存的信息转换为某种类型的数据结构,然后保存并加载此数据结构。

例如

def save(self):
    data = {"name": self.name,
            "nodes": self.nodes,
            ...
           }
    with open('data.json', 'w') as f:
        json.dump(data, f)

def load(self):
    with open('data.json') as f:
        data = json.load(f)
    self.name = data["name"]
    self.nodes = data["nodes"]
    ...

如果您要存储的任何值包含对tkinter对象的引用(例如:小部件,画布项ID列表等),您必须将它们转换为其他值,并在启动时恢复它们

答案 1 :(得分:0)

除了Brian Oakley提出的建议之外,还可以将数据另存为莳萝导出:

def save(self):
    data = {"name": self.name,
            "nodes": self.nodes,
            ...
           }
    with open('data.pkl', 'wb') as f:
        dill.dump(data, f)

def load(self):
    with open('data.pkl', 'rb') as f:
        data = dill.load(f)
    self.name = data["name"]
    self.nodes = data["nodes"]
    ...

请注意,在此处必须在打开文件时指定二进制模式。