我想生成n个不同的Tkinter按钮。我有这段代码:
import Tkinter as tk
for i in range(boardWidth):
newButton = tk.Button(root, text=str(i+1),
command=lambda: Board.playColumn(i+1, Board.getCurrentPlayer()))
Board.boardButtons.append(newButton)
如果boardWidth是5,虽然我得到标记为1-5的按钮,但点击时它们都会执行Board.playColumn(5,Board.getCurrentPlayer())。
我需要第一个按钮来执行Board.playColumn(1,Board.getCurrentPlayer()),第二个按钮来执行Board.playColumn(2,Board.getCurrentPlayer())等等。
感谢您的帮助!
答案 0 :(得分:11)
我认为问题是lambda
在i
循环结束后正在获取for
的最终值。这应该解决(未经测试):
import Tkinter as tk
for i in range(boardWidth):
newButton = tk.Button(root, text=str(i+1),
command=lambda j=i+1: Board.playColumn(j, Board.getCurrentPlayer()))
Board.boardButtons.append(newButton)
<强>更新强>
BTW,这是通过在lambda
函数中添加一个参数来实现的,该参数的默认值是在循环中创建每个函数时从i
的值计算的,而不是返回到最终i
在其中的表达式稍后执行时通过闭包的值。
答案 1 :(得分:2)
您的问题是您在同一名称空间中创建了大量lambda
个对象,而lambda
个引用了外部作用域中的名称。这意味着它们不会成为闭包,并且它们不会存储对象的引用,直到以后......当它发生时,所有lambdas都将引用i
的最后一个值。
尝试使用回调工厂来解决这个问题:
import Tkinter as tk
def callbackFactory(b, n):
def _callback():
return b.playColumn(n, b.getCurrentPlayer())
return _callback
for i in range(boardWidth):
newButton = tk.Button(root, text=str(i+1),
command=callbackFactory(Board, i+1))
Board.boardButtons.append(newButton)
另一个想法是将i的当前值存储为lambda
对象中的默认参数值,而不是依赖于闭包行为来存储引用:
for i in range(boardWidth):
newButton = tk.Button(root, text=str(i+1),
command=lambda x=i: Board.playColumn(x+1, Board.getCurrentPlayer()))
Board.boardButtons.append(newButton)