lambda中的变量范围

时间:2013-02-06 21:08:59

标签: python scope

为什么此代码打印“d,d,d,d”,而不是“a,b,c,d”?如何修改它以打印“a,b,c,d”?

cons = []
for i in ['a', 'b', 'c', 'd']: 
    cons.append(lambda: i)  
print ', '.join([fn() for fn in cons])      

4 个答案:

答案 0 :(得分:6)

奇怪的是,这不是一个变量的范围问题,而是对python的for循环(以及python变量)语义的质疑。

如您所料,lambda中的i正确引用最近的封闭范围中的变量i。到目前为止,非常好。

但是,您希望这意味着会发生以下情况:

for each value in the list ['a', 'b', 'c', 'd']: 
    instantiate a new variable, i, pointing to the current list member
    instantiate a new anonymous function, which returns i
    append this function to cons

实际发生的是:

instantiate a new variable i
for each value in the list ['a', 'b', 'c', 'd']: 
    make i refer to the current list member
    instantiate a new anonymous function, which returns i
    append this function to cons

因此,您的代码将相同的变量i追加到列表中四次 - 当循环退出时,i的值为{{ 1}}。

请注意,如果python函数接受并通过 value 返回其参数/返回值的值,您将不会注意到这一点,因为{{1}的内容 }将在每次调用'd'时复制(或者,就此而言,在使用i创建的匿名函数的每次返回时)。但实际上,python变量总是引用到特定对象 - 因此,append的四个副本在循环结束时都引用lambda。 / p>

答案 1 :(得分:2)

创建闭包时,lambdas“封闭”的变量(在本例中为i)受名称限制,而不是值。因此,每当你打电话给你的lambdas时,他们都会使用'i'的最后一个值。

答案 2 :(得分:2)

以下是您需要做的简单修复:

cons = []
for i in ['a', 'b', 'c', 'd']: 
    cons.append(lambda i=i: i)  
print ', '.join([fn() for fn in cons])     

答案 3 :(得分:0)

'Erics'的回答是理解:

 cons =[lambda i= i:i for i in ['a', 'b', 'c', 'd']]   
 print ', '.join([fn() for fn in cons])