【问题标题】:Python enclosing scope variables with lambda functionPython用lambda函数封闭范围变量
【发布时间】: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)

提前致谢

【问题讨论】:

    标签: python list for-loop lambda


    【解决方案1】:

    我会尽力把它分解成更简单的术语

    第一 -

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

    第二次

    现在.. AFTER for 循环完成了它的迭代。for 循环中“i”的值将是“4”。 -- lambda 函数不包含“i”的任何值,因为您还没有调用它。

    第三次

    当您调用 lambda 函数时,只有函数会在循环完成了它的迭代;这是“4”

    第 4 次

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

    【讨论】:

      【解决方案2】:

      尽管i 随着时间的推移采用多个值,但实际上只有一个变量ii 的内容在循环期间被更改。但是闭包捕获的是变量,而不是值。在您调用它之前,不会在 lambda 内部进行任何评估。在您调用该函数时,您会访问i 的当前值,它恰好是最后一个值。

      至于为什么i=i 解决了这个问题,这在The Hitchhiker's guide to Python 中有解释(Common Gotchas):

      Python 的默认参数在定义函数时计算一次,而不是每次调用函数时(就像在 Ruby 中一样)。这意味着,如果您使用可变的默认参数并对其进行变异,那么您将并且已经对该对象进行了变异,以便将来调用该函数。

      因此,在您创建的闭包内部发生的每个新绑定(并且恰好被命名为i,就像外面的绑定一样)在创建闭包时计算其默认值。因此,您拥有“正确”的值,可以在调用闭包时使用。

      【讨论】:

        【解决方案3】:

        首先,观察列表中的所有 5 个函数都是相同的,因为它们都使用 makelist 内部的 finalmakelist

        但是,

        i 是在评估 lambda 表达式时创建的 闭包 的一部分。这意味着如果您在从makelist 调用函数的范围内为i 分配一个新值,这不会影响任何函数。他们从作为闭包结果附加到函数的命名空间中查找i 的值,而不是从全局范围中查找。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-04-28
          • 2016-11-13
          • 1970-01-01
          • 1970-01-01
          • 2013-10-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多