2016-11-23 8 views
0

Ich versuche, meine Füße nass mit Gurke zu bekommen, so schreibe ich ein wenig Beispielcode wie folgt aus:Verwenden Gurke einen Zustand für die Klasse zu laden

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

So ist das Ziel dieser Anwendung ist, wenn ich getroffen die Plus-Taste, wird eine zunehmende Anzahl auf dem Bildschirm angezeigt. Und wenn ich es speichere, schließe das Fenster, öffne es wieder und drücke die Lade-Taste, ich sehe, wann ich das letzte Mal die Nummer erhöht habe. Ich bin sehr neu für Gurke, und der aktuelle Code gibt diese zurück zu mir:

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 

Ich frage mich, was das Problem hier ist. Außerdem sehe ich eine Menge Tutorials oder Beispielcode online, die tut Dinge wie:

with open('save_game.dat', 'wb') as f: 
    player= pickle.load 

Was bedeutet with bedeuten?

+0

[ '' 'with''' in der docs] (https://docs.python.org/3/reference/compound_stmts.html#the-with-statement) - wenn sie mit einem Dateiobjekt verwendet Es stellt sicher, dass die Datei geschlossen wird, selbst wenn eine Ausnahme ausgelöst wird. Es gibt viele Referenzen online, diese könnte helfen - http://effbot.org/zone/python-with-statement.htm. Hier ist ein SO Q & A - http://stackoverflow.com/q/1369526/2823755 – wwii

+0

Normalerweise sollten Sie immer die komplette Traceback in Ihre Fragen buchen. – wwii

+0

'' 'def __getstate __ (self):' '' sieht problematisch aus - was gibt es zurück, wenn man es * manuell * nennt? – wwii

Antwort

4

Ihr Problem kann auf eine kleine Klasse vereinfacht werden, die nicht tkinter überhaupt zu verwenden ist:

>>> 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 

Du Beizen des __getstate__ Instanz-Methode, nicht den vollen Zustand der start Klasse. Python lässt Sie das tun, vorausgesetzt, Sie implementieren auch eine __setstate__-Methode, die weiß, wie man ein Objekt aus diesen Informationen rekonstruiert. Vom docs:

Nach Unpickling, wenn die Klasse __setstate __() definiert, wird es mit dem ungebeizten Zustand bezeichnet. In diesem Fall ist es nicht erforderlich, dass das Zustandsobjekt ein Wörterbuch ist. Andernfalls muss der gebeizte Zustand ein Wörterbuch sein, und seine Elemente werden dem Wörterbuch der neuen Instanz zugewiesen.

Wenn Sie unpickle erstellt Gurke eine neue Instanz von state aber da die Klasse keine __setstate__ Methode hat, Gurke versucht, den Objekt __dict__ wiederherzustellen. Das schlägt fehl, weil das nicht gepunktete Objekt eine Instanzmethode ist, kein dict. Und das zeigt ein größeres Problem mit Ihrem Ansatz.

pickle erstellt vollständige Objekte neu, es wird nicht in vorhandenen Objekten wiederhergestellt. Wenn Sie in Ihrem Fall das gesamte start Objekt einlegen, wird ein zweites start Objekt zusätzlich zu dem Objekt, das Sie selbst erstellt haben, wiederhergestellt. Sie könnten die dieses Objekts Ihrem __dict__ zuweisen, aber das ist ein sehr riskantes Angebot. Sie würden den gesamten Zustand Ihres Frame-Objekts zugunsten dessen verlieren, was sich in dem Objekt befindet, das Sie gebeizt haben. Es ist wahrscheinlich unmöglich, das gesamte Objekt zu putzen, da tkinter ein C-Erweiterungsmodul ist.

Stattdessen sollten Sie die Daten, die Sie speichern und wiederherstellen möchten, von dem tkinter-Objekt trennen, das Sie zur Interaktion mit dem Benutzer verwenden. Dies ist eine allgemeine Programmierregel: separate Daten von der Präsentation. Hier habe ich eine Klasse, die Daten enthält und ich kann sie separat von der Klasse tkinter speichern und wiederherstellen.

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() 
+0

Vielen Dank! Das ist sehr klar! – angieShroom

+0

@angieShroom - froh, ich könnte helfen. Wenn dies für Sie funktioniert, akzeptieren Sie es als Antwort, damit andere es wissen. – tdelaney

Verwandte Themen