我正在尝试在Python(Tkinter)中运行一个(GUI)程序,该程序应该如下工作:
一个循环生成五个(或者通常是n,我只是尝试为n = 5现在这样做)按钮,然后点击第i个按钮打印出来。这是我做的:
def func(i):
print i
for i in range(5):
buttons[i]= Button(but, text= "%s" %str(inputs[i]), command= lambda: func(i+1))
buttons[i].grid(row= i+2, column= 0)
问题是,点击所有按钮打印5,所以不知何故func(5)被分配给所有按钮。令人惊讶的是,做了以下工作。
buttons[0].config(command= lambda: func(1))
buttons[1].config(command= lambda: func(2))
buttons[2].config(command= lambda: func(3))
buttons[3].config(command= lambda: func(4))
buttons[4].config(command= lambda: func(5))
由于我正在尝试对任意数量的输入执行此操作,因此没有其他方法可以在没有循环的情况下执行此操作。有谁可以帮我解决这个问题?谢谢!
答案 0 :(得分:2)
与许多其他人一样,你已成为lambda illusion的受害者。即使您正在创建5个函数对象,它们都是相同的,因为所有5个函数对象都具有相同的主体,并且在调用任何函数之前不会评估正文中的名称“i”。您的代码等同于
def func(j):
print j
def cmd():
func(i+1)
for i in range(5):
buttons[i] = Button(but, text="%s" % str(inputs[i]), command=cmd)
buttons[i].grid(row= i+2, column= 0)
很明显,您将相同的命令附加到每个按钮,按任意按钮将使用i的最终值,即4.要获得5个不同的函数,请删除{ {1}}并将def cmd
替换为以下任一项:
command=cmd
我强烈建议在不同的函数中使用不同的参数名,尤其不要重复使用循环变量名作为循环中定义的函数的参数名。在3.x中,您可以删除func并使用
command=lambda j=i: func(j+1)
command=lambda j=i+1: func(j)
答案 1 :(得分:1)
问题是可变范围之一。变量i
在这里是你的全局范围,因此lambdas都使用同一个变量,它具有按下按钮时的值(即5)。
最简单的解决方法是用lambda j=i+1: func(j)
替换你的lambda。
这声明了一个新变量(j
),它仅在值的范围内定义,并在声明lambda时赋予i + 1的值。