我们在使用lambda函数的时候常常会遇到这样的问题
lambda函数虽然写好了,但是不够灵活,
比如说,我们在lambda函数中使用一个参数i
在定义参数i的时候它还是指向正确的值,
隔一段时间,它被程序修改了,那么就可能会指向错误的值
导致lambda函数执行时发生不可预测的异常,甚至有时候还没有error
tk.Button(window, text=i + '日志记录', command=lambda:CreateView(i,"Log",Rewrite_data.read_txt(i))).pack()
以tkinter中按钮点击事件传递参数为例
上面这种写法,是打算用循环遍历创建按钮,对于每个按钮传递一个i值作为command回调的参数
但是事与愿违,刚创建的i值很快就会被遍历的下一个循环所覆盖,等到执行按钮回调函数的时候早已不是当初的i值,甚至会因为执行了其他函数,连i值的类型都发生变化。幸好我发现类型变化了,才能快速找到是lambda函数的问题
那么直接给出解决方法吧
第一种是冻结法
tk.Button(window, text=i + '日志记录', command=(lambda i : lambda:CreateView(i,"Log",Rewrite_data.read_txt(i)))(i)).pack()
在lambda函数外再次嵌套一个lambda函数,把i值传递到外层lambda执行一次
a = (lambda i: lambda : print(i))(1)
b = lambda i=1:print(i)
a()
b()
用最简单的方法就可以验证lambda函数的冻结原理
无论是外层lambda还是 lambda 参数赋值,原理都是先执行一次i值的初始化
初始化部分,也就是冒号前面的内容,执行是动态的,相当于冒号后面的函数的构造
c = lambda i: lambda : print(i)
>>> c(1)
<function <lambda>.<locals>.<lambda> at 0x0000022DC471FD38>
>>> c(2)
<function <lambda>.<locals>.<lambda> at 0x0000022DC472D318>
如果改用双重lambda的方式来写,那么每次调用c都会构造一个新的lambda函数
可以动态地构造函数
f = 1
d = lambda i=f:print(i)
>>> d()
1
>>> f = 2
>>> d()
1
如果采用lambda参数赋值的方式来写,那么每次调用lambda都是一样的参数值,在第一次lambda定义的时候就已经成为了静态函数。
最后感谢codeday大佬的技术分享,为我带来了思路 http://www.cocoachina.com/cms/wap.php?action=article&id=66693