Python中将lambda存入数组后按位置调用总是执行最后一个函数是什么原因?
问题产生原因
这个问题是Python的*迟绑定(late binding)*特性导致的:闭包(这里的lambda函数)中引用的外部变量,是在函数调用时才会去查找对应的值,而不是在函数定义时就捕获变量的当前值。
你在循环中创建lambda的时候,所有lambda都共享同一个循环变量i,整个循环结束后i的最终值是9,所以后续你调用任意一个lambda时,查到的i都是9,自然全输出9。
至于你设置pos=1时结果符合预期,本质是巧合:你调用函数的循环同样用了i作为迭代变量,每次调用funcs[i]()时,当前循环的i刚好和函数创建时的迭代值一致,所以看起来结果正确。你只要把调用循环的变量名改成j,就会发现输出还是全为9,问题依然存在。
正确实现方案
核心思路是在lambda定义阶段就把当前的i值固定下来,常用的有三种方案:
方案1:使用默认参数捕获当前值
Python中函数的默认参数是在函数定义时求值的,我们可以把当前迭代的i作为默认参数传给lambda,就能把值固定下来:
for i in l: funcs.append(lambda i=i: print(i))
方案2:使用functools.partial固定参数
partial会在创建时就把传入的参数和函数绑定,也能实现值的固化:
from functools import partial for i in l: funcs.append(partial(print, i))
方案3:用嵌套函数创建独立作用域
额外写一层包装函数,每次迭代时调用包装函数传入当前的i,利用函数作用域保存对应的值:
def make_func(i): return lambda: print(i) for i in l: funcs.append(make_func(i))
以上任意一种方案修改后,不管你按哪种方式调用数组中的函数,都会正确输出创建时对应的值。
内容的提问来源于stack exchange,提问作者mybrainisrunningoutofmyears
相关产品推荐
相关产品推荐

