Python中列表推导式为何与for循环执行结果不一致?
为什么字典中存储的lambda函数在列表推导式中调用会返回相同结果?
我使用Python 3.10版本,排查了一周的bug后发现是列表推导式未给出预期结果导致的。以下是复现代码:
alist = [1,2,3] d = {} for a in alist: d[a] = lambda x: a + x print([d[a](1) for a in alist]) for a in alist: print(d[a](1))
执行结果:
[4, 4, 4] 2 3 4
原因分析
这是Python中闭包的延迟绑定特性导致的。你定义的lambda函数lambda x: a + x并没有在循环时立即捕获当前a的值,而是在函数被调用的时候才会去查找变量a的当前值。
当循环for a in alist结束后,变量a的值已经变成了列表的最后一个元素3。此时执行列表推导式[d[a](1) for a in alist],虽然推导式里的a依次取1、2、3,但调用d[a](1)时,lambda内部引用的a是外层作用域的那个a(也就是循环结束后的3),所以每次计算都是3+1=4,得到[4,4,4]。
而后面的for a in alist循环中,每次迭代都会重新给a赋值为1、2、3,此时调用d[a](1)时,lambda查找的a是当前循环迭代的a值,所以会得到2、3、4的正确结果。
解决办法
如果想让lambda在定义时就绑定当前循环的a值,可以通过默认参数的方式强制绑定:
alist = [1,2,3] d = {} for a in alist: d[a] = lambda x, a=a: a + x # 用默认参数绑定当前a的值 print([d[a](1) for a in alist]) # 输出 [2,3,4]
这样每次循环时,a的当前值会被作为默认参数存入lambda,后续调用时就会使用这个绑定的值,而不是去查找外层作用域的a。
内容的提问来源于stack exchange,提问作者Valir23
相关产品推荐
相关产品推荐

