Python用lambda函数包含范围变量

时间:2016-12-06 14:02:43

标签: python list for-loop lambda

我写了这个简单的代码:

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)

提前致谢

3 个答案:

答案 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;作为进行计算的论据。