再加上@sepp2k的答案,你会看到这两种不同的行为,因为正在创建的lambda函数不知道从哪里得到i的值。在创建这个函数时,它只知道它必须从本地范围、封闭范围、全局范围或内置函数中获取i的值。在
在这种特殊情况下,它是一个闭包变量(封闭范围)。它的值随每次迭代而变化。在
现在来解释为什么第二个像预期的那样工作,而第一个却没有?
这是因为每次生成一个lambda函数时,生成器函数的执行就会停止,而当您调用它时,它将使用i的值。但是在第一种情况下,我们已经在调用任何函数之前将i的值提升到9。在
为了证明这一点,您可以从__closure__的单元格内容中获取i的当前值:>>> for func in test_with_yield():
print "Current value of i is {}".format(func.__closure__[0].cell_contents)
print func(9)
...
Current value of i is 0
Current value of i is 1
Current value of i is 2
Current value of i is 3
Current value of i is 4
Current value of i is 5
Current value of i is 6
...
但是,如果您将函数存储在某个地方,稍后再调用它们,您将看到与第一次相同的行为:
^{pr2}$
输出:Current value of i is 0
Current value of i is 1
Current value of i is 2
Current value of i is 3
Now value of i is 3
Now value of i is 3
Now value of i is 3
Now value of i is 3
Patrick Haugh in comments使用的示例也显示了相同的情况:sum(t(1) for t in list(test_with_yield()))
正确方法:
将i作为默认值赋给lambda,默认值是在创建函数时计算的,它们不会更改(unless it's a mutable object)。i现在是lambda函数的局部变量。在>>> def test_without_closure():
return [lambda x, i=i: x+i for i in range(10)]
...
>>> sum(t(1) for t in test_without_closure())
55