用lambda函数封装Python中的闭包变量

6
我写了这段简单的代码:
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)

Thanks in advance


这个回答解决了你的问题吗?在循环中创建函数 - outis
3个回答

5
尽管变量i会随时间改变多个值,实际上只有一个变量i。在循环期间,i的内容正在被更改。但是闭包捕获变量,而不是值。在调用函数之前,lambda内部没有任何计算。当你调用该函数时,你访问的是i的当前值,这恰好是最后一个值。
至于为什么i=i解决了问题,在The Hitchhiker's guide to Python(Common Gotchas)中有解释:
Python的默认参数在定义函数时只会计算一次,而不是每次调用函数时都计算(就像Ruby一样)。这意味着如果您使用可变的默认参数并对其进行修改,则您将为所有将来调用该函数的对象进行了修改。
因此,每个在闭包内创建的新绑定(恰好命名为与外部相同的i),其默认值在创建闭包时被计算。因此,当调用闭包时,你已经准备好了“正确”的值。

3
首先,注意列表中的所有5个函数都是相同的,因为它们都使用了来自makelist内部的ifinal值。
然而,i是在评估lambda表达式时创建的闭包的一部分。这意味着,如果您在调用makelist中的函数时在作用域中为i赋新值,则不会影响任何函数。它们从与闭包相关联的函数命名空间中查找i的值,而不是从全局作用域中查找。

0

我会尽力用更简单的术语来解释一下

第一点 -

for循环正在循环并将“未调用”的lambda函数附加到列表中。--在您的示例中,它将执行5次。

第二点 -

现在... for循环完成其迭代之后.. "i"的值将为"4"。--lambda函数不包含任何“i”的值,因为您尚未调用它。

第三点 -

当您调用lambda函数时,只有函数才会查找记住循环完成迭代时“i”的值; 即为“4”

第四点 -

Lambda然后插入“4”作为参数进行计算。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接