2016-10-10 7 views
-1

メソッド呼び出しの使い方の違いを理解するために、私はPython 2.7でMVCを書きました。ここでは、コードは次のようになります。Python - 起動時のself.method、lambda:self.method()とself.method()の違い

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

1がそれを実行し、ラベルを更新するにはボタンを押した場合、その結果は以下の通りです:

enter image description here

1が見ることができるように、model.self.data["Value_One"]がオンに設定されていません私は名前のない関数であると考えていたlambdaを使用していたため、1つの値だけ返すことができました。ここでは、ボタンset_v_oneのコマンドラインによるメソッドの最初の呼び出しを禁止するようです。

model.self.data["Value_Two"]の場合、値は起動時に更新されます。私はthatsだと思うと、ボタンのコマンドラインが読み込まれ、ボタンが作成され、アクティブな呼び出しやブラケットを介してメソッドの初期化のために()が起こるので、そうでないときでさえボタンをパックします。

model.self.data["Value_Three"]については、起動時に値も更新されません。これは、コントローラのset_value_three(self)メソッドがコマンドラインにバインドされているが、初期化されていないため、ブラケット()を使用して呼び出すことができないために発生したと考えられます。

対応するラベルlabel_onelabel_threeによって示されるように、ボタンset_v_oneset_v_threeを押すと、値が正しく、更新されます。

私はこれらのメソッド呼び出しをたくさん使用していますが、どのように詳細に機能しているかはまだ完全には理解できませんでした。誰かがこれを明らかにしたり、私がまだ見つけていない良い情報源を指摘してくれたら、それは大いに感謝しています。

+2

'self.method < - メソッドへの参照'、 'self.method()< - メソッドを呼び出す'。 lambdaは呼び出し可能にするだけで 'lambda:self.method()'を使用している場合は 'self.method'を使用することもできます。 –

答えて

2

ここには謎はありません。

ボタンコンストラクタのコマンド引数は、コールバック、つまりボタンが押されたときに実行される関数をとります。これはボタン1と3で行います。したがって、対応するボタンがクリックされると、関数(ラムダまたはバインドされたメソッド)が呼び出され、ラベルが更新されます。ボタン2では、実際には2番目のラベルの値を設定するメソッドを実行し、そのメソッド呼び出しの結果をコマンド引数に割り当てます(Noneになります)。これは私が理解する限りAPIに違反しており、おそらくエラーになるはずです。

これをまとめると、関数(実行可能なオブジェクト)とその呼び出し(関数を実行する動作)が混ざり合っているように見えます。

+0

この場合、 'lambda'は、メソッドを指すラッパーとして機能します。メソッドには、' lambda'によって呼び出される戻り値が2つ以上ない限り呼び出されます。 – MrPadlog

+0

ラムダは関数を定義するための単なるショートカットです。あなたの場合、それは 'def myfun():self.controller.set_value_one()'と同じで、 'command = myfun' – MrMobster

関連する問題