python - Lambda 函数在 Python 3 和 Python 2 中的行为不同

标签 python python-3.x lambda python-2.x

为什么要写这段代码

>>> 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/

相关文章:

python - 无法使用 python-requests 获取 "Content-Disposition: attachment;"的网页

Python- Selenium : Scroll down not working because of PopUp

python - 基于字典中的一个键的字典列表中的一个值的总和

python - Azure Python SDK : 'ServicePrincipalCredentials' object has no attribute 'get_token'

visual-studio - 在 Visual Studio 2019 中的 lambda 表达式中使用 x

JAVA 11 - 可选 - 类中无效的方法引用方法 isPresent 可选 - 无法从静态上下文中引用非静态方法

python - 想要了解 Spark Streaming 的工作原理吗?

python - 使用 Selenium 抓取 Understat 图表数据的问题

python - 如何反转集合中的树状链接?

java - java Lambda表达式,传递参数