为什么要写这段代码
>>> i=1
>>> add_one=lambda x:x+i
>>> my_list=[add_one(i) for i in [0,1,2]]
在 Python 2.7 中抛出这个结果:
>>> my_list
[0, 2, 4]
但是 Python 3.3 中的相同代码会抛出另一个结果:
>>> my_list
[1, 2, 3]
Python 2.7 的结果对我来说更有意义,因为“i”变量与调用 lambda 函数的名称范围相同。我不理解 Python 的两个分支中 lambda 函数的这些不平等行为。
最佳答案
不同之处在于,在 Python 3 中,列表推导式不会将其变量泄漏到封闭范围内。你可以看到 Guido 对此的一些讨论 here ;该帖子包含一个与您的示例非常相似的示例。
在这两个版本中,您的add_one(i)
都是一个引用变量i
的函数。调用函数时,将在封闭范围内按名称查找此变量。由于该函数是在全局模块级别定义的,因此“封闭范围”是全局范围。这意味着当您调用 add_one
时,它将使用它在全局范围内找到的 i
的任何值(即,它将查找名为 i< 的全局变量
)。
在 Python 2 中,列表理解将其变量 i
泄漏到封闭范围。由于您的列表理解是在全局模块级范围内,因此“封闭范围”再次是全局的,并且泄漏的变量 i
是一个全局变量,覆盖了您最初用 设置的值i = 1
行。调用 add_one
然后引用这个变量。由于 i
随每次迭代而变化,因此您的函数在每次迭代时有效地执行 i+i
。
在 Python 3 中,列表理解在私有(private)范围内创建自己的变量。但是您的函数仍然访问全局 i
。由于 Python 3 列表理解不会泄漏到全局范围,这个全局 i
永远不会改变,并且你的函数在每次迭代时有效地执行 x+1
(其中 x
是列表理解的循环变量)。
关于python - Lambda 函数在 Python 3 和 Python 2 中的行为不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22288604/