绑定事件之后,Tkinter如何处理lambda?

Tom*_*Tom 0 python lambda tkinter

我正在尝试编写一些代码,这些代码将Entry根据绑定将盒子的值发送给函数。从技术上讲,我可以在下面的代码中获得所需的行为,但是我a)不知道为什么会这样,并且b)非常确定我没有以最pythonic的方式执行此操作。我敢肯定,我误解的eventlambda或两者兼而有之。

在绑定触发时,在Entry框下方的代码中input_box1,该inp_var1.get()代码仅获取默认值,而不获取任何已输入到该框中的内容。换句话说,该test1函数将打印...

Test1 Foo

...无论您输入什么内容。

上的绑定input_box2完全符合我的预期。我在其中键入任何内容,然后单击其他位置,它会打印新条目。但是我不明白为什么我lambda不想要event或为什么我需要重复inp_var2.get()通话。

如果有人知道引擎盖下发生了什么,我很想听听!这是代码:

from tkinter import *
from tkinter import ttk

def test1(event, i):
    print('Test1', i)

def test2(event, i):
    print('Test2', i)

root = Tk()
title_label = Label(root, text='This does not work!')
title_label.grid(column=0, row=0)

inp_var1 = StringVar(value='Foo')
input_box1 = Entry(root, textvariable=inp_var1)
input_box1.grid(column=0, row=1)

inp_var2 = StringVar(value='Bar')
input_box2 = Entry(root, textvariable=inp_var2)
input_box2.grid(column=0, row=2)

input_box1.bind('<FocusOut>', lambda event, i=inp_var1.get(): test1(event, i))
input_box2.bind('<FocusOut>', lambda i=inp_var2.get(): test2(i, inp_var2.get()))

root.mainloop()
Run Code Online (Sandbox Code Playgroud)

tor*_*rek 7

这与Tkinter本身无关。lambda一般而言,它与Python的连接并不多。

将这两个都排除在外,并考虑以下Python程序:

def f(x=3, y=4):
    print('x =', x, 'y =', y)

f(0, 0)
f(0)
f()
Run Code Online (Sandbox Code Playgroud)

假设Python 3(或from __future__ import print_function)在运行时显示:

x = 0 y = 0
x = 0 y = 4
x = 3 y = 4
Run Code Online (Sandbox Code Playgroud)

这是因为第一次调用fpass 0, 0,所以xand y都绑定为零。传递的第二个调用f正是0如此x0y绑定到其默认值4。第三个调用完全不传递任何值,x并且y都绑定到其默认值。

(到目前为止,这一切都应该足够清楚。)

现在让我们大惊小怪。我将继续假设使用Python 3,这input意味着我们必须使用Python 2 raw_input实现以下功能:

def f(x=input('enter default x: '), y=input('enter default y: ')):
    print('x =', x, 'y =', y)

print('about to call f three times')
f(0, 0)
f(0)
f()
Run Code Online (Sandbox Code Playgroud)

在运行此示例程序之前,请考虑一下您期望它做什么。然后运行它-这是我的结果:

$ python3 t.py
enter default x: hello
enter default y: world
about to call f three times
x = 0 y = 0
x = 0 y = world
x = hello y = world
Run Code Online (Sandbox Code Playgroud)

为什么会出现这种读取默认值,xy 之前我们甚至把它称为第一次?为什么没有它读取新的默认值x,并y在每次调用?

考虑一下,然后继续阅读

真的,那样做。询问为什么在这些奇怪的时间发生输入。

现在您已经考虑过...

确实做到了。这就是关键。执行语句时将捕获参数的默认值。该语句将名称绑定到我们的函数,实际上是在看到函数体后,在Python加载文件时运行的。在Python到达调用之后,再到第一次调用之后,函数本身将稍后运行。defdeffprintf

lambdaPython中的A 只是一种匿名函数定义。代替:

def square(x):
    return x * x
Run Code Online (Sandbox Code Playgroud)

我们可以这样写:

square = lambda x: x * x
Run Code Online (Sandbox Code Playgroud)

lambda表达式定义了一个新的功能状物品,一个lambda函数 -你不能使用if/ else类型里面这些,只是表达一个语句,它们会自动返回其表达式的值。在这种情况下,我们的lambda函数有一个名为的参数x。函数返回x * x

外部分配square =将该lambda函数绑定到名称square,就像我们做的def square(x)那样。因此,这基本上只是一个语法技巧:我们可以有一个square带有参数的真实函数(如带参数),或者一个只能使用表达式的有限的lambda函数,如我们几乎立即绑定到name的匿名函数square

尽管参数部分的工作方式相同。与f和一样input,如果我们绑定x

square = lambda x=3: x * x
Run Code Online (Sandbox Code Playgroud)

要么:

square = lambda x=int(input('choose a default for x now> ')): x * x
Run Code Online (Sandbox Code Playgroud)

当表达式本身执行时,这种情况只会发生一次lambda。该函数现在具有一个x带有默认值的变量。

稍后,当我们调用该函数时,我们可以为提供一个值x,或者将其设置为默认值。如果不提供值,Python将在执行其中的行时(而不是现在)调用lambda函数时使用它先前捕获的默认值lambda

这对于Tkinter也同样适用。你写了:

input_box2.bind('<FocusOut>', lambda i=inp_var2.get(): test2(i, inp_var2.get()))
Run Code Online (Sandbox Code Playgroud)

但这几乎与写作相同:

def f(i=inp_var2.get()):
    test2(i, inp_var2.get())

input_box2.bind('<FocusOut>', f)
Run Code Online (Sandbox Code Playgroud)

除了您不必在这里提供函数名f。该函数的lambda变体没有名称,但仍然只是一个函数。(为此,square = lambda ...lambda函数没有名称。名称square是变量的名称,而不是函数的名称。变量仅绑定到函数,因此可以square(10)调用它。)

无论如何,稍后,当Tkinter具有匹配的事件时<FocusOut>,Tkinter会调用f...,或者(如果使用的话lambda)会调用未命名的lambda函数。Tkinter为该函数提供了一个参数。它提供的一个参数是事件。因此,对于您的默认值if上面是无关紧要的,你可以这样做:

def f(i=None):
    test2(i, inp_var2.get())
Run Code Online (Sandbox Code Playgroud)

要么:

def f(i='hello world'):
    test2(i, inp_var2.get())
Run Code Online (Sandbox Code Playgroud)

因为当Tkinter调用时f,它总是为i