Python - self.method、lambda 之间的区别:启动时 self.method() 和 self.method()

Python - difference between self.method, lambda: self.method() and self.method() on startup

为了理解方法调用的使用差异,我在python2.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()

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

可以看到,启动时没有设置model.self.data["Value_One"],因为使用了lambda,我以为是无名函数,只能return一个价值仅此而已。这里好像是禁止按钮set_v_one.

的命令行对方​​法的初始调用

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

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

按下按钮 set_v_oneset_v_three 后,值会正确更新,如相应标签 label_onelabel_three 所示。

尽管我经常使用这些方法调用,但我还不能完全理解它们的详细工作原理。如果有人可以澄清这一点或指出我尚未找到的良好来源,将不胜感激。

总而言之,这里没有什么神秘之处。

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

综上所述,您的困惑似乎源于混淆了函数(可以执行的对象)及其调用(执行函数的动作)。