Python用lambda函数封闭范围变量
Posted
技术标签:
【中文标题】Python用lambda函数封闭范围变量【英文标题】:Python enclosing scope variables with lambda function 【发布时间】:2017-04-21 04:47:52 【问题描述】:我写了这个简单的代码:
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)
提前致谢
【问题讨论】:
【参考方案1】:我会尽力把它分解成更简单的术语
第一 -
for 循环正在循环并将 'uncall' lambda 函数附加到列表中。 --在您的示例中,它将执行 5 次。
第二次
现在.. AFTER for 循环完成了它的迭代。for 循环中“i”的值将是“4”。 -- lambda 函数不包含“i”的任何值,因为您还没有调用它。
第三次
当您调用 lambda 函数时,只有函数会在循环完成了它的迭代;这是“4”
第 4 次
Lambda 然后插入“4”作为参数来进行计算。
【讨论】:
【参考方案2】:尽管i
随着时间的推移采用多个值,但实际上只有一个变量,i
。 i
的内容在循环期间被更改。但是闭包捕获的是变量,而不是值。在您调用它之前,不会在 lambda 内部进行任何评估。在您调用该函数时,您会访问i
的当前值,它恰好是最后一个值。
至于为什么i=i
解决了这个问题,这在The Hitchhiker's guide to Python 中有解释(Common Gotchas):
Python 的默认参数在定义函数时计算一次,而不是每次调用函数时(就像在 Ruby 中一样)。这意味着,如果您使用可变的默认参数并对其进行变异,那么您将并且已经对该对象进行了变异,以便将来调用该函数。
因此,在您创建的闭包内部发生的每个新绑定(并且恰好被命名为i
,就像外面的绑定一样)在创建闭包时计算其默认值。因此,您拥有“正确”的值,可以在调用闭包时使用。
【讨论】:
【参考方案3】:首先,观察列表中的所有 5 个函数都是相同的,因为它们都使用 makelist
内部的 final 值 makelist
。
i
是在评估 lambda
表达式时创建的 闭包 的一部分。这意味着如果您在从makelist
调用函数的范围内为i
分配一个新值,这不会影响任何函数。他们从作为闭包结果附加到函数的命名空间中查找i
的值,而不是从全局范围中查找。
【讨论】:
以上是关于Python用lambda函数封闭范围变量的主要内容,如果未能解决你的问题,请参考以下文章