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_one
和 set_v_three
后,值会正确更新,如相应标签 label_one
和 label_three
所示。
尽管我经常使用这些方法调用,但我还不能完全理解它们的详细工作原理。如果有人可以澄清这一点或指出我尚未找到的良好来源,将不胜感激。
总而言之,这里没有什么神秘之处。
Button 构造函数的命令参数采用回调,即按下按钮时将执行的函数。您对按钮 1 和 3 执行此操作。因此,当单击相应的按钮时,将调用函数(无论是 lambda 还是绑定方法)并更新标签。使用按钮二,您实际上执行了设置第二个标签值的方法,并将该方法调用的结果(将为 None)分配给命令参数。据我所知,这违反了 API 并且可能会导致错误。
综上所述,您的困惑似乎源于混淆了函数(可以执行的对象)及其调用(执行函数的动作)。
为了理解方法调用的使用差异,我在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_one
和 set_v_three
后,值会正确更新,如相应标签 label_one
和 label_three
所示。
尽管我经常使用这些方法调用,但我还不能完全理解它们的详细工作原理。如果有人可以澄清这一点或指出我尚未找到的良好来源,将不胜感激。
总而言之,这里没有什么神秘之处。
Button 构造函数的命令参数采用回调,即按下按钮时将执行的函数。您对按钮 1 和 3 执行此操作。因此,当单击相应的按钮时,将调用函数(无论是 lambda 还是绑定方法)并更新标签。使用按钮二,您实际上执行了设置第二个标签值的方法,并将该方法调用的结果(将为 None)分配给命令参数。据我所知,这违反了 API 并且可能会导致错误。
综上所述,您的困惑似乎源于混淆了函数(可以执行的对象)及其调用(执行函数的动作)。