我正在尝试编写一些代码,该代码将根据绑定将Entry
框的值发送给函数。从技术上讲,我可以在下面的代码中获得所需的行为,但是我a)不知道为什么会这样,并且b)非常确定我没有以最pythonic的方式执行此操作。我敢肯定我误解了event
或lambda
或两者。
在绑定触发时,在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()
答案 0 :(得分:6)
这与Tkinter本身无关。与lambda
的连接也没有那么多,通常与Python的连接也没有。
将这两个都排除在外,并考虑以下Python程序:
def f(x=3, y=4):
print('x =', x, 'y =', y)
f(0, 0)
f(0)
f()
假设Python 3(或from __future__ import print_function
)在运行时显示:
x = 0 y = 0
x = 0 y = 4
x = 3 y = 4
这是因为对f
的 first 调用传递了0, 0
,因此x
和y
都绑定为零。对f
的 second 调用仅传递0
,因此x
绑定到0
,而y
绑定到其默认值4. third 调用完全不传递任何内容,并且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()
在运行此示例程序之前,请考虑您希望它执行的操作。然后运行它-这是我的结果:
$ 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
为什么在我们甚至第一次调用它之前,都读取了x
和y
的默认值?为什么没有在每次通话时都读取x
和y
的新默认值?
真的,这样做。问问为什么在这些奇怪的时间发生输入。
它做到了 。这就是关键。您的参数的默认值在执行def
语句时被捕获 。当def
语句将名称f
绑定到我们的函数时,实际上是在看到函数体后Python加载文件时 run 。在Python进行print
调用,然后进行第一个f
调用之后,函数本身将稍后运行。
Python中的lambda
只是一种匿名函数定义。代替:
def square(x):
return x * x
我们可以写:
square = lambda x: x * x
lambda
表达式定义了一个类似于函数的新项,即 lambda函数-您不能在其中一个中使用if
/ else
类型的语句这些,只是表达式,它们会自动返回其表达式的值。在这种情况下,我们的lambda函数具有一个名为x
的参数。该函数返回x * x
。
外部赋值square =
将此lambda函数绑定到名称square
,就像我们做了def square(x)
一样。因此,这基本上只是一个语法技巧:我们可以有一个带有参数的实函数,例如square
,或者一个只能使用表达式的有限的lambda函数,例如这个几乎立即绑定到名称{{ 1}}。
参数部分的工作方式相同。与square
和f
一样,如果我们绑定input
:
x
或:
square = lambda x=3: x * x
仅在square = lambda x=int(input('choose a default for x now> ')): x * x
表达式本身执行时一次发生。 功能现在具有一个变量lambda
,具有默认值。
稍后,当我们调用该函数时,我们可以为x
提供一个值,或者将其设置为默认值。如果我们不提供值,则当我们执行其中带有x
的行时(而不是现在)调用lambda函数时,Python将使用它捕获更早的默认值。
这对Tkinter也同样适用。您写道:
lambda
但这与写作几乎相同:
input_box2.bind('<FocusOut>', lambda i=inp_var2.get(): test2(i, inp_var2.get()))
,除了您不必在此处提供函数名def f(i=inp_var2.get()):
test2(i, inp_var2.get())
input_box2.bind('<FocusOut>', f)
。该函数的lambda变体没有名称,但仍然只是一个函数。 (因此,当我们执行f
时,lambda函数没有名称。名称square = lambda ...
是变量的名称,而不是函数的名称。变量只是< em>绑定到该函数,以便square
对其进行调用。)
无论如何,稍后,当Tkinter的事件与square(10)
相匹配时,Tkinter会调用<FocusOut>
...,或者,如果您使用了f
,则会调用您的未命名的lambda函数。 Tkinter为该函数提供了一个参数。它提供的一个参数是事件。因此,上面lambda
中i
的默认值是无关紧要的,您可以这样做:
f
或:
def f(i=None):
test2(i, inp_var2.get())
因为Tkinter调用def f(i='hello world'):
test2(i, inp_var2.get())
时,它总是为f
提供实际参数。