泡菜不能与tkinter一起使用 [英] Pickle will not work with tkinter

查看:107
本文介绍了泡菜不能与tkinter一起使用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在用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.

解决方案

最简单的答案是,您不能腌制任何与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列表等),则必须将它们转换为其他内容,并在启动时将其还原. /p>

I'm making a little game with Tkinter, and it has a save function using pickle. However, when I try to save, it throws up the following message;

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

The thing is, the data I'm trying to pickle contains nothing Tkinter-related, so I don't understand why it says it is <class 'tkapp'>
Here is a summary of the relevant bits of code:

...
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()

How can I fix this? I've tried changing __getstate__ as suggested in a related question, but it didn't work.

EDIT: Never mind, it turns out that deep in my data structure, I had left a BooleanVar.

解决方案

The short answer is, you can't pickle anything tkinter related. The reason is that tkinter applications use an embedded Tcl interpreter which maintains the state of the GUI in memory, and Tcl doesn't know anything about the python pickle format (and likewise, pickle knows nothing about the tcl interpreter). There's simply no way to save and restore the data managed by the Tcl interpreter.

You will have to convert the information you want to save into some type of data structure, and then save and load this data structure.

For example

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"]
    ...

If any of the values you want to store contain references to tkinter objects (eg: widgets, list of canvas item ids, etc.), you'll have to convert them to something else, and restore them at startup.

这篇关于泡菜不能与tkinter一起使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆