在 Python 中,Yielding 不会创建闭包,而 lambda 会创建闭包。在“test_without_closure”中得到全 9 的原因并不是因为没有闭包。如果没有,您将无法访问i
根本不。问题是所有闭包都包含对同一 i 变量的引用,该变量在函数末尾为 9。
这种情况与test_with_yield
。那么,为什么会得到不同的结果呢?因为yield
暂停函数的运行,因此可以在到达函数末尾之前(即之前)使用生成的 lambdai
是 9。要了解这意味着什么,请考虑以下两个使用示例test_with_yield
:
[f(0) for f in test_with_yield()]
# Result: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[f(0) for f in list(test_with_yield())]
# Result: [9, 9, 9, 9, 9, 9, 9, 9, 9, 9]
这里发生的情况是,第一个示例生成一个 lambda(当 i 为 0 时),调用它(i 仍然为 0),然后前进该函数直到生成另一个 lambda(i 现在为 1),调用该 lambda,依此类推。重要的是每个 lambda 在控制流返回之前被调用test_with_yield
(即在 i 的值改变之前)。
在第二个示例中,我们首先创建一个列表。因此,第一个 lambda 被生成(i 为 0)并放入列表中,第二个 lambda 被创建(i 现在为 1)并放入列表中......直到最后一个 lambda 被生成(i 现在为 9)并放入进入列表。和then我们开始调用 lambda。所以自从i
现在是 9,所有 lambda 都返回 9。
1 这里重要的一点是闭包保存对变量的引用,而不是创建闭包时它们所保存的值的副本。这样,如果您分配给 lambda 内部的变量(或内部函数,它以与 lambda 相同的方式创建闭包),这也会更改 lambda 外部的变量,如果您更改外部的值,则该更改将是在 lambda 内部可见。