从pd.DataFrame创建lambda函数字典时的结果异常问题排查
问题:循环中生成Lambda函数时的变量绑定陷阱
场景说明
有一个校准曲线参数文件dummy_calcurve.csv,内容如下:
repeat,method,slope,intercept a,linear,2,3 b,linear,4,5
想要生成一个字典calcurve,每个键对应一个lambda函数,通过calcurve['a'](x)完成对应条件下的校准计算。编写的代码及输出如下:
calcurve = {} ccs = pd.read_csv('dummy_calcurve.csv', index_col=0) for repeat in ccs.index: slope = ccs.slope[repeat] intercept = ccs.intercept[repeat] print(repeat, slope, intercept) calcurve[repeat] = lambda x : slope * x + intercept print(calcurve['a'](0)) print(calcurve['b'](0))
输出结果:
a 2 3 b 4 5 5 5
预期输出是3和5,但实际两个lambda函数都使用了第二组('b')的参数,中间打印的参数却是正确的,问题出在哪里?
原因分析
Lambda函数采用延迟绑定机制:它不会在定义时捕获slope和intercept的当前值,而是在调用时才去查找这两个变量的当前引用。当循环结束后,slope和intercept已经被更新为最后一次循环的取值(即'b'组的4和5),所以两个lambda函数调用时都会使用这组值,导致结果不符合预期。
解决办法
方法1:使用默认参数捕获当前值
在定义lambda时,把slope和intercept作为默认参数,这样就能在定义时捕获当前循环的变量值:
calcurve = {} ccs = pd.read_csv('dummy_calcurve.csv', index_col=0) for repeat in ccs.index: slope = ccs.slope[repeat] intercept = ccs.intercept[repeat] print(repeat, slope, intercept) calcurve[repeat] = lambda x, s=slope, i=intercept : s * x + i print(calcurve['a'](0)) # 输出3 print(calcurve['b'](0)) # 输出5
方法2:使用函数工厂创建闭包
通过一个外部函数来生成lambda,利用闭包特性捕获当前循环的变量值:
def create_cal_func(slope, intercept): return lambda x: slope * x + intercept calcurve = {} ccs = pd.read_csv('dummy_calcurve.csv', index_col=0) for repeat in ccs.index: slope = ccs.slope[repeat] intercept = ccs.intercept[repeat] print(repeat, slope, intercept) calcurve[repeat] = create_cal_func(slope, intercept) print(calcurve['a'](0)) # 输出3 print(calcurve['b'](0)) # 输出5
内容的提问来源于stack exchange,提问作者Ben Zeen
相关产品推荐
相关产品推荐

