当你想用循环语句在tkinter或者无论某个函参中写一个带参的函数,你可能会碰到这样的错误:
def e(n):
print("E", n)
t = []
for i in range(10):
t.append(lambda: e(i))
for p in t:
p()
#Output
E 9
E 9
E 9
E 9
E 9
E 9
E 9
E 9
E 9
E 9
Code language: PHP (php)
以上尽管直接看不常见,但是会出现在很多tkinter语句中,比如tkinter的按钮:
import tkinter as tk
root = tk.Tk()
def pr(xxx):
print(xxx)
for i in range(10):
g = tk.Button(root, text = str(i),
command = lambda: pr(i)
)
g.pack()
root.mainloop()
Code language: JavaScript (javascript)
看到问题出现在哪了吗?
你想要给每个按钮触发事件一个ID,但是tkinter触发事件直接用 command = xxx 不能带参数,所以你选择了匿名函数。
但是这又出现了一个问题,正如开头所讲,这样的格式最后会导致 变量 i 变成循环最后一个数字。
匿名函数如同正常函数一样,不会在定义时就直接获取ID,而是调用后再获取,因此会变成图中的 9 (即 range(10)[-1])
如何解决?
不要想着将值赋给按钮对象,因为匿名函数获取的按钮对象也是最后一个按钮。
command = lambda n=i: pr(n) #将原command参数这一行替换即可
Code language: PHP (php)
函数参数的默认值会立即获取,所以n就是当前的i。
扩展一下,我在一本书上看过,似乎当一个函数的参数默认为列表时候:
def f(n, a=[]):
a.append(n)
print(a)
Code language: PHP (php)
你执行第一次f(1),第二次f(2),第三次f(3),上面的 a 参数会依旧保存上一次执行时候的值。
听不明白?没关系: