【问题标题】:Understanding the flow of this Python code了解此 Python 代码的流程
【发布时间】:2020-08-16 19:36:28
【问题描述】:

我在网上看到了这段代码,不知道它是如何工作的。

def multipliers():
    return [lambda x : i * x for i in range(4)]

print([m(2) for m in multipliers()])

这里有一些问题:

  1. 乘法器函数返回的列表的输出是什么?
  2. 这里的m(2) 是什么意思?因为它没有在代码中的任何地方提到什么是 m 。但是代码仍然可以正常工作。

【问题讨论】:

  • 2.列表推导中提到了“m”。
  • 嗯。这段代码对我来说有令人惊讶的行为。我希望 multipliers() 会返回一个包含四个不同 lambda 的列表,当使用 x = 2 进行评估时,它们会返回不同的值。但它会打印 [6, 6, 6, 6]。关于这些 lambdas 是如何创建的,我没有关注什么?

标签: python late-binding


【解决方案1】:

multipliers 返回函数列表的函数(更确切地说是一些匿名函数,也就是 lambdas):


multipliers()

# the return of multipliers function
[<function multipliers.<locals>.<listcomp>.<lambda> at 0x11243c048>, <function multipliers.<locals>.<listcomp>.<lambda> at 0x11243c0d0>, <function multipliers.<locals>.<listcomp>.<lambda> at 0x11243c158>, <function multipliers.<locals>.<listcomp>.<lambda> at 0x11243c1e0>]

[m(2) for m in multipliers()] 列表解析,您可以在其中迭代并调用 multipliers 返回的列表中的每个函数。

问题是 python 闭包是后期绑定的,这意味着闭包中使用的变量的值是在调用它的内部函数时查找的 (lambda x : i * x for i in range(4))

这就是为什么对于您的情况,打印列表是 [6, 6, 6, 6],因为列表中的函数(由 multipliers 返回)实际上看起来像这样 lambda x : 3 * x 并且当您迭代和调用列表中的每个 lambda理解[m(2) for m in multipliers()] 你实际上是在调用或多或少相同的函数

如果你想“修复”multipliers 函数的行为,你可以这样做:


def fix_multipliers():
    return [ lambda x, i=i: i*x for i in range(4)]

之后你会看到“预期的”行为:

print([m(2) for m in fix_multipliers()]) [0, 2, 4, 6]

PS:闭包是一个函数对象,它记住封闭范围内的值,即使它们不存在于内存中,也就是扩展内部函数的范围。

【讨论】:

  • 是否可以强制 Python 更早地绑定变量,从而实际打印 [0, 2, 4, 6]? ETA:哦,太好了!
  • 以上捕获是这样做的
【解决方案2】:

上述代码的输出将是 [6, 6, 6, 6](不是 [0, 2, 4, 6])。

原因是 Python 的闭包是late binding。这意味着在调用内部函数时会查看闭包中使用的变量的值。因此,当调用multipliers() 返回的任何函数时,会在当时的周围范围内查找i 的值。到那时,无论调用哪个返回函数,for 循环都已完成,i 的最终值为 3。因此,每个返回的函数都将其传递的值乘以 3,因此,由于上面的代码中传递了 2 的值,它们都返回 6 的值(即 3 x 2)。

换句话说,lambda 在调用时返回 i 的值。 lambda 在循环完成后被调用,所以在它被调用时 i 是 3。

【讨论】:

  • 这很好,但没有回答问题。
  • 所以基本上 lambda 在调用时返回 i 的值。循环结束后调用 lambda,所以在调用它时 i 为 3。
  • 这两个问题都没有解决。
猜你喜欢
  • 1970-01-01
  • 2017-02-15
  • 2018-08-05
  • 2021-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-23
相关资源
最近更新 更多