Python循环创建Lambda函数列表时参数引用异常问题排查
循环生成带参数的正弦函数列表的闭包陷阱
你想要基于列表lst = [0, 50, 75, 83, 98, 84, 32]生成对应的正弦函数列表,期望得到[0, sin(50x), sin(75x), sin(83x), sin(98x), sin(84x), sin(32x)],但你写的代码:
function = [] lst = [0, 50, 75, 83, 98, 84, 32] for m in lst: function.append(lambda x : np.sin(m*x))
出现了错误:调用function[0](1)得到的不是预期的0,而是0.5514266812416906(也就是sin(32*1)的结果)。
问题原因
这是Python闭包的延迟绑定特性导致的:循环中创建的lambda函数并不会捕获循环变量m的当前值,而是捕获变量m的引用。当你后续调用这些lambda函数时,它们才会去读取m的当前值——而循环结束后,m已经指向列表的最后一个元素32,所以所有lambda函数都会使用m=32来计算。
解决方法
有三种常用的方式可以避免这个陷阱:
方法1:使用默认参数绑定当前值
在lambda中添加默认参数m=m,这样每次循环时,m的当前值会被作为默认参数固定下来,而不是引用变量:
import numpy as np function = [] lst = [0, 50, 75, 83, 98, 84, 32] for m in lst: function.append(lambda x, m=m: np.sin(m*x)) # 验证结果 print(function[0](1)) # 输出 0.0,符合预期 print(function[1](1)) # 输出 sin(50) ≈ -0.26237485370392877
方法2:使用functools.partial包装函数
partial可以帮你预先绑定函数的参数值,生成新的函数:
import numpy as np from functools import partial function = [] lst = [0, 50, 75, 83, 98, 84, 32] for m in lst: # 先定义接收m和x的函数,再绑定m的当前值 sin_func = partial(lambda m, x: np.sin(m*x), m) function.append(sin_func) # 验证结果 print(function[0](1)) # 输出 0.0 print(function[2](1)) # 输出 sin(75) ≈ -0.38778163540943045
方法3:定义辅助函数生成闭包
通过一个辅助函数来创建lambda,利用函数参数的局部作用域固定m的值:
import numpy as np def create_sin_function(m): # 这里的m是函数参数,属于局部变量,会保存当前传入的值 return lambda x: np.sin(m*x) function = [] lst = [0, 50, 75, 83, 98, 84, 32] for m in lst: function.append(create_sin_function(m)) # 验证结果 print(function[0](1)) # 输出 0.0 print(function[-1](1)) # 输出 sin(32) ≈ 0.5514266812416906
内容的提问来源于stack exchange,提问作者Amelia
相关产品推荐
相关产品推荐

