Python列表推导生成lambda全返回最后值,能否关闭对应优化?
问题原因说明
你遇到的输出异常不是Python针对lambda的特殊优化,而是Python闭包的迟绑定特性决定的:闭包内部引用的外层变量,只会在闭包函数实际被调用时才会去查找对应的值,而非闭包定义时就捕获变量的当前值。你在列表推导中定义的所有lambda都引用了迭代变量elt,当你后续调用这些lambda时,elt已经循环到了最后一个值5,因此所有调用输出都是5。
这是Python作用域设计的固有规则,不存在开关可以关闭或者弱化该逻辑。
可实现预期效果的替代方案
方案1:利用默认参数在定义时捕获值
Python中函数的默认参数会在函数定义阶段完成求值,我们可以把当前迭代的elt赋值给lambda的默认参数,让每个lambda都保存对应迭代的elt值:
tab = [lambda elt=elt: elt for elt in [1,2,3,4,5]] for elt in tab: print(elt())
方案2:用functools.partial提前绑定参数
通过functools.partial可以把当前迭代的elt作为固定参数预先绑定到函数上,避免后续变量变更带来的影响:
from functools import partial tab = [partial(lambda x: x, elt) for elt in [1,2,3,4,5]] for elt in tab: print(elt())
方案3:用高阶函数创建独立作用域
我们可以编写一个辅助函数封装lambda的创建逻辑,每次调用辅助函数都会生成独立的作用域保存当前的elt值:
def create_lambda(val): return lambda: val tab = [create_lambda(elt) for elt in [1,2,3,4,5]] for elt in tab: print(elt())
以上三种方案运行后都会输出你预期的1、2、3、4、5序列。
内容的提问来源于stack exchange,提问作者JosephConrad
相关产品推荐
相关产品推荐

