(正如'homework'标签所示,这是计算机科学中 big 项目的一部分。)
我正在使用tkinter在Python中编写 Jeopardy!模拟,我在按钮中使用lambda函数时遇到了很大的问题。假设root = Tk()
和categories
是一个列表。
# Variable to keep the buttons
root._buttons = {}
# Display headers on top of page
for i in range(5):
# Get category name for display in main window
name = categories[i]
b = Label(root, text=fill(name.upper(), 10), width=18, height=3,\
bg="darkblue", fg="white", font=("Helvetica bold", "", 11))
b.grid(row=0, column=i)
# Create list of buttons in that variable (root._buttons)
btnlist = [None]*5
# Display individual questions
for j in range(5):
# Make a button for the question
b = Button(root, text="$" + str(200 * (j+1)), width=8, height=1,
bg="darkblue", fg="orange", font=("Impact", "", 30))
b.cat = name
b.value = 200 * (j + 1)
b.sel = lambda: select(b.cat, b.value)
# Add callback event to button
print(b.cat, b.value, b.sel)
b.config(command=b.sel)
# Add button to window
b.grid(row=j+1, column=i)
# Append to list
btnlist[j] = b
root._buttons[categories[i]] = btnlist
有关所有代码,请参阅my little Code Viewer (under construction!)
问题似乎发生在lambda: select(b.cat, b.value)
,因为当我点击电路板上的任何按钮时,它总是会转到电路板上的最后一个按钮。我尝试了其他方法,不幸的是全部使用lambda
,我还没有看到任何不涉及lambda
的方法。
答案 0 :(得分:8)
更改
lambda: select(b.cat, b.value)
到
lambda b = b: select(b.cat, b.value)
在原始代码中,b
不是lambda
的局部变量;它在封闭范围内找到。完成for-loop
后,b
会保留最后一个值。这就是为什么lambda
函数都使用最后一个按钮。
如果将lambda定义为使用默认值获取一个参数,则在lambda 定义时确定(并修复)默认值。现在b
是lambda
的局部变量,当没有参数调用lambda时,Python将b
设置为默认值,根据需要可以愉快地设置为各种不同的按钮。
答案 1 :(得分:0)
如果用函数工厂替换lambda表达式,它会让你更具表现力。 (假设你打算多次打电话)。这样你就可以在不必处理lambda限制的情况下进行分配,添加更复杂的逻辑等。
例如:
def button_factory(b):
def bsel():
""" button associated with question"""
return select(b.cat, b.value)
return bsel
给定输入b
,button_factory
返回一个可调用()
的函数,该函数可以返回您想要的内容。唯一的区别是你可以做作业等。
尽管最初可能会占用更多代码,但以后会为您提供更大的灵活性。 (例如,您可以将计数器附加到bsel并且能够计算选择特定问题的次数等)。
它还有助于内省,因为您可以使每个文档字符串清楚地识别与之关联的问题等。