2016-10-10 3 views
-1

Um den Unterschied in der Verwendung von Methodenaufrufen zu verstehen, schrieb ich eine MVC in Python 2.7. Hier ist der Code:Python - Unterschied zwischen self.method, Lambda: self.method() und self.method() beim Start

import Tkinter as tk 

class Model(object): 
    def __init__(self, *args, **kwargs): 
     # dict 
     self.data = {} 
     # -- >values 
     self.data["Value_One"] = tk.IntVar() 
     self.data["Value_Two"] = tk.IntVar() 
     self.data["Value_Three"] = tk.IntVar() 
     # --> texts 
     self.data["Text_Label_val_One"] = tk.StringVar() 
     self.data["Text_Label_val_Two"] = tk.StringVar() 
     self.data["Text_Label_val_Three"] = tk.StringVar() 

class Control(tk.Tk): 
    def __init__(self, *args, **kwargs): 
     tk.Tk.__init__(self, *args, **kwargs) # init 
     tk.Tk.wm_title(self, "Testing Grounds") # title 

     self.model = Model() 
     self.view = View(parent = self, controller = self) 
     self.view.pack(fill = 'both', expand = True) 

    def set_labels_text(self): 
     self.model.data["Text_Label_val_One"].set("Value_One is set to: {0}".format(self.model.data["Value_One"].get())) 
     self.model.data["Text_Label_val_Two"].set("Value_Two is set to: {0}".format(self.model.data["Value_Two"].get())) 
     self.model.data["Text_Label_val_Three"].set("Value_Three is set to: {0}".format(self.model.data["Value_Three"].get())) 

    def set_value_one(self): 
     self.model.data["Value_One"].set(1)  

    def set_value_two(self): 
     self.model.data["Value_Two"].set(2) 

    def set_value_three(self): 
     self.model.data["Value_Three"].set(3) 

class View(tk.Frame): 
    def __init__(self, parent, controller): 
     tk.Frame.__init__(self, parent) 
     self.controller = controller 

     self.buttons() 
     self.labels() 

    def buttons(self): 
     set_v_one = tk.Button(self, text = "Set Value One To 1", command = lambda: self.controller.set_value_one()) 
     set_v_one.pack(fill = 'x', expand = True) 

     set_v_two = tk.Button(self, text = "Set Value Two To 2", command = self.controller.set_value_two()) 
     set_v_two.pack(fill = 'x', expand = True) 

     set_v_three = tk.Button(self, text = "Set Value Three To 3", command = self.controller.set_value_three) 
     set_v_three.pack(fill = 'x', expand = True) 

     update_lbl_two = tk.Button(self, text = "Update Labels", command = self.controller.set_labels_text) 
     update_lbl_two.pack(fill = 'x') 

    def labels(self): 
     label_one = tk.Label(self, textvariable = self.controller.model.data["Value_One"]) 
     label_one.pack(fill = 'x', expand = True) 

     label_two = tk.Label(self, textvariable = self.controller.model.data["Value_Two"]) 
     label_two.pack(fill = 'x', expand = True) 

     label_three = tk.Label(self, textvariable = self.controller.model.data["Value_Three"]) 
     label_three.pack(fill = 'x', expand = True)   

     label_val_one = tk.Label(self, textvariable = self.controller.model.data["Text_Label_val_One"]) 
     label_val_one.pack(fill = 'x', expand = True) 

     label_val_two = tk.Label(self, textvariable = self.controller.model.data["Text_Label_val_Two"]) 
     label_val_two.pack(fill = 'x', expand = True) 

     label_val_three = tk.Label(self, textvariable = self.controller.model.data["Text_Label_val_Three"]) 
     label_val_three.pack(fill = 'x', expand = True) 

if __name__ == "__main__": 
    app = Control() 
    app.mainloop() 

Wenn man es ausführt und trifft auf die Schaltfläche, um die Etiketten zu aktualisieren, ist das Ergebnis folgendes:

enter image description here

Wie man sehen kann, ist model.self.data["Value_One"] nicht festgelegt auf Start, wegen der Verwendung von lambda, die ich für eine namenlose Funktion hielt, die nur einen Wert und nichts mehr zurückgeben kann. Hier scheint es den ersten Aufruf der Methode durch die Befehlszeile der Schaltfläche set_v_one zu verhindern.

Bei model.self.data["Value_Two"] wird der Wert beim Start aktualisiert. Ich denke, das ist, weil die Funktion aufgerufen wird, wenn die Befehlszeile der Schaltfläche gelesen wird und die Schaltfläche aufgrund des aktiven Aufrufs oder der Initialisierung der Methode über die Brakets () erstellt wird, da dies auch dann geschieht, wenn dies nicht der Fall ist pack den Knopf ein.

Für model.self.data["Value_Three"] wird der Wert auch beim Start nicht aktualisiert. Dies ist, wie ich denke, durch die Methode set_value_three(self) des Controllers an die Befehlszeile gebunden, aber nicht initialisiert, aufgrund des fehlenden Aufrufs dafür durch die Verwendung der Brakets ().

Nach Drücken der Tasten set_v_one und set_v_three, erhalten die Werte korrekt aktualisiert, wie durch die entsprechenden Etiketten angegeben label_one und label_three.

Auch wenn ich diese Methodenaufrufe oft nutze, konnte ich noch nicht ganz verstehen, wie sie im Detail arbeiten. Wenn jemand das klären könnte oder mich auf eine gute Quelle verweisen könnte, die ich noch nicht gefunden habe, würde es sehr geschätzt werden.

+2

'self.method <- Referenz auf die Methode', 'self.method() <- Methode aufrufen. Sie können auch 'self.method' verwenden, wenn Sie' lambda: self.method() 'verwenden, da das Lambda es nur aufrufbar macht. –

Antwort

2

Alles in allem gibt es hier kein Geheimnis.

Das Befehlsargument des Button-Konstruktors nimmt einen Rückruf, d. H. Eine Funktion, die ausgeführt wird, wenn die Schaltfläche gedrückt wird. Dies tun Sie für die Schaltflächen 1 und 3. Wenn Sie also auf die entsprechenden Schaltflächen klicken, wird die Funktion (sei es die Lambda-Methode oder die gebundene Methode) aufgerufen, und die Beschriftungen werden aktualisiert. Mit der zweiten Schaltfläche führen Sie tatsächlich die Methode aus, die den Wert der zweiten Beschriftung festlegt und dem Befehlsargument das Ergebnis dieses Methodenaufrufs zuweist (das ist None). Dies verstößt soweit ich weiß, gegen die API und sollte wahrscheinlich zu einem Fehler führen.

Um es zusammenzufassen, scheint Ihre Verwirrung aus der Vermischung einer Funktion (ein Objekt, das ausgeführt werden kann) und seines Aufrufs (die Aktion der Ausführung einer Funktion) zu stammen.

+0

Also funktioniert in diesem Fall 'lambda' als Wrapper, der auf die Methode verweist, die aufgerufen werden soll, solange es in der Methode nicht mehr als einen Rückgabewert gibt, der mit' lambda' aufgerufen wird? – MrPadlog

+0

Das Lambda ist nur eine Abkürzung für die Definition einer Funktion. In Ihrem Fall ist es äquivalent zu 'def myfun(): self.controller.set_value_one()' und dann 'command = myfun' – MrMobster

Verwandte Themen