Python - 启动时{self}方法,lambda:self.method()和self.method()之间的区别

时间:2016-10-10 11:18:11

标签: python lambda method-call

为了理解方法调用的使用差异,我在python 2.7中编写了一个MVC。这是代码:

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

如果执行它并点击按钮更新标签,结果如下:

enter image description here

正如我们所看到的,model.self.data["Value_One"]未在启动时设置,因为使用了lambda,我认为它是一个无名函数,它只返回一个值,而不是更多。这里似乎通过按钮set_v_one的命令行禁止方法的初始调用。

model.self.data["Value_Two"]的情况下,该值在启动时更新。我认为这是因为函数被调用,当读取按钮的命令行并创建按钮时,由于活动调用或通过brakets ()初始化该方法,因为它确实发生了,即使一个人没有包装按钮。

对于model.self.data["Value_Three"],该值在启动时也不会更新。正如我所想的那样,这是由绑定到命令行的控制器的set_value_three(self)引起的,但由于没有通过使用brakets ()来调用它而没有初始化

按下set_v_oneset_v_three按钮后,值会得到正确更新,相应的标签为label_onelabel_three

即使我使用这些方法调用很多,但我还不能完全理解它们的工作原理。如果有人能够澄清这一点或者指出一个我尚未找到的良好来源,那将非常感激。

1 个答案:

答案 0 :(得分:2)

总而言之,这里没有任何谜团。

Button构造函数的命令参数采用回调,即按下按钮时将执行的函数。您可以对按钮1和3执行此操作。因此,当单击相应的按钮时,将调用函数(无论是lambda还是绑定方法)并更新标签。使用按钮2,您实际上执行设置第二个标签值的方法,并为命令参数分配该方法调用的结果(将为None)。据我所知,这违反了API,可能会导致错误。

总结一下,你的困惑似乎源于混合了一个函数(一个可以执行的对象)和它的调用(执行一个函数的动作)。