简体   繁体   English

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

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

In order to understand the difference in use of method calls, I wrote a MVC in python 2.7. 为了理解使用方法调用的区别,我在python 2.7中编写了MVC。 Here is the code: 这是代码:

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

If one executes it and hits the button to update the labels, the result is the following: 如果执行该命令并单击按钮以更新标签,则结果如下:

在此处输入图片说明

As one can see, model.self.data["Value_One"] is not set on startup, due to the use of lambda , which I thought to be a nameless function, which can only return one value and nothing more. 可以看到,由于使用了lambda ,因此未在启动时设置model.self.data["Value_One"] ,我认为这是一个无名函数,只能返回一个值,仅此而已。 Here it seems to inhibit the initial call of the method by the command line of button set_v_one . 在这里,似乎通过按钮set_v_one的命set_v_one了方法的初始调用。

In the case of model.self.data["Value_Two"] , the value is updated on startup. 对于model.self.data["Value_Two"] ,该值在启动时更新。 I'd think thats because the function is called, when the command line of the button is read and the button created, due to the active call or initialization of the method via brakets () , because it does happen, even when one doesn't pack the button. 我认为那是因为在读取按钮的命令行并创建按钮时调用了该函数,这是由于主动调用或通过刹车()初始化了该方法,因为它的确发生了,即使没有这样做也是如此。打包按钮。

For model.self.data["Value_Three"] , the value is also not updated on startup. 对于model.self.data["Value_Three"] ,该值也不会在启动时更新。 This is, as I'd think, caused by the method set_value_three(self) of the controller bound to the command line, but not initialized, due to the lack of calling for it by using the brakets () . 我想这是由绑定到命令行的控制器的set_value_three(self)方法引起的,但是由于没有使用brickts ()进行调用而未初始化,因此未初始化。

After pressing the buttons set_v_one and set_v_three , the values get properly updated, as indicated by the corresponding labels label_one and label_three . 按下按钮set_v_oneset_v_three ,值将正确更新,如相应的标签label_onelabel_three

Even though I'm using these method calls a lot, I couldn't yet fully understand, how they work in detail. 即使我经常使用这些方法调用,但我还无法完全了解它们的详细工作原理。 If someone could clarify this or point me to a good source I just haven't found yet, it would be much appreciated. 如果有人可以澄清这一点或为我提供一个我还没有找到的好消息来源,将不胜感激。

All in all, there is no mystery here. 总而言之,这里没有谜。

The command argument of the Button constructor takes a callback, ie a function that will be executed when the button is pressed. Button构造函数的command参数接受回调,即当按下按钮时将执行的函数。 You do this for buttons 1 and 3. So when the corresponding buttons are clicked, the function (be it the lambda or the bound method) is called and the labels are updated. 您可以对按钮1和3进行此操作。因此,当单击相应的按钮时,将调用函数(即lambda或bound方法)并更新标签。 With button two, you actually execute the method that sets the value of the second label and assigning the command argument the result of that method call (which will be None). 使用按钮2,您实际上执行的方法是设置第二个标签的值,并将该方法调用的结果分配给命令参数(将为None)。 This is in violation of the API as far as I understand and should probably result in an error. 据我了解,这违反了API,可能会导致错误。

To sum it up, your confusion seems to stem from mixing up a function (an object that can be executed) and its invocation (the action of executing a function). 综上所述,您的困惑似乎源于混淆了一个函数(一个可以执行的对象)及其调用(执行一个函数的动作)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM