我写了这个简单的代码:
def makelist():
L = []
for i in range(5):
L.append(lambda x: i**x)
return L
好的,现在我打电话给
mylist = makelist()
因为稍后调用嵌套函数时会查找封闭的范围变量,所以它们都有效地记住了相同的值: 因此,我希望在最后一次循环迭代中找到循环变量的值,但是当我检查我的列表时,我看到:
>>> mylist[0](0)
1
>>> mylist[0](1)
4
>>> mylist[0](2)
16
>>>
我很困惑,为什么我的代码不保留最后一个for循环值?为什么我不必使用默认参数显式保留封闭的范围值,如下所示:
L.append(lambda x, i=i: i ** x)
提前致谢
答案 0 :(得分:4)
即使i
随着时间的推移需要多个值,实际上只有一个变量,i
。循环期间i
的内容正在更改。但是闭包捕获变量,而不是值。在调用它之前,lambda中没有任何内容被评估。在您调用该函数时,您将访问当前值i
,这恰好是最后一个值。
至于i=i
解决问题的原因,例如在The Hitchhiker's guide to Python( Common Gotchas )中解释了这一点:
Python的默认参数在定义函数时被计算一次,而不是每次调用函数时(比如Ruby)。这意味着如果你使用一个可变的默认参数并对其进行变异,那么你将会对该对象进行变异,以便将来调用该函数。
因此,在您创建的闭包内发生的每个新绑定(恰好被命名为i
就像外部一样)在创建闭包时会计算其默认值。因此,您具有“正确”值,可以在调用闭包时使用。
答案 1 :(得分:3)
首先,请注意列表中的所有5个函数都是相同的,因为它们都使用i
内的makelist
的最终值。
i
是评估lambda
表达式时创建的闭包的一部分。这意味着,如果您在i
中调用函数的范围内为makelist
分配新值,则不会影响任何函数。作为闭包的结果,它们从附加到函数的命名空间中查找i
的值,而不是来自全局范围。
答案 2 :(得分:0)
我会尽我所能用更简单的术语来分解它
1st -
for循环正在循环播放并附加' 未调用' lambda函数列表。 - 在你的例子中,它会做5次。
<强> 第二 强>
现在.. AFTER for循环完成它的迭代...&#34; i&#34;在for循环中将是&#34; 4&#34;。 - lambda函数不包含&#34; i&#34;因为你还没有调用它。
<强> 第三 强>
当您调用lambda函数时,只有 ,该函数才能查看&#39; 记住&#39;变量&#34; i&#34;的值当循环完成它的迭代时;这是&#34; 4&#34;
<强> 第四 强>
Lambda然后插入&#34; 4&#34;作为进行计算的论据。