为什么tkinter按钮lambda绑定的变量始终是列表的最后一项?
问题原因
该问题由Python闭包的迟绑定特性导致:
- 按钮的
text属性在循环执行过程中实时赋值,每次迭代都会直接读取当前room_type[i]的值绑定到按钮文本,因此显示完全正常。 lambda函数内引用的变量i不会在定义时立即求值,只有当按钮被点击、lambda实际执行时才会查找i的当前值。循环执行完成后i已经固定为列表最后一个元素的索引,因此所有按钮触发new_room时传入的都是最后一个房间类型。
解决方法
方法1:给lambda添加默认参数(最简方案)
Python函数的默认参数会在函数定义时完成求值,利用该特性可以把每次迭代的当前值绑定到lambda的参数上,只需修改按钮的command参数即可:
# 修改command参数为带默认值的lambda command=lambda r=room_type[i]: new_room(r)
修改后的完整循环代码如下:
for i in range(len(room_type)): globals()[f'{room_type[i]}_add'] = Button(root, text='Add a ' + room_type[i], command=lambda r=room_type[i]: new_room(r)) globals()[f'{room_type[i]}_add'].grid(row=1, column=i)
方法2:使用functools.partial绑定参数
functools.partial会在实例化时就把传入的参数固定到目标函数上,也可以规避迟绑定问题:
首先导入partial:
from functools import partial
修改command参数:
command=partial(new_room, room_type[i])
内容的提问来源于stack exchange,提问作者progress456
相关产品推荐
相关产品推荐

