列表推导中定义的变量是不是会泄漏到封闭范围内? [复制]

Posted

技术标签:

【中文标题】列表推导中定义的变量是不是会泄漏到封闭范围内? [复制]【英文标题】:Do variables defined inside list comprehensions leak into the enclosing scope? [duplicate]列表推导中定义的变量是否会泄漏到封闭范围内? [复制] 【发布时间】:2015-07-02 20:20:36 【问题描述】:

我找不到任何定义这种行为的地方:

if [x for x in [0, 1, -1] if x > 0]:
    val = x

这段代码有多安全?如果列表中的任何元素大于 0,val 是否总是分配给列表中的最后一个元素?

【问题讨论】:

我试过了(在 python 2.6.6 上,但我想差别不大),对我来说结果是 -1。我想这与列表理解的工作方式有关。我认为首先替换值,然后检查 if 子句。 (顺便说一句,我有点惊讶 x 在理解范围之外......) 谢谢,我在问题中打错字了,在循环结束时 val 似乎总是等于 -1 我假设如果返回一个列表,那么 x 将始终保持等于最后一个元素在列表中,或者至少看起来是这样。我也很惊讶 x 仍在范围内。 当我使用上面的代码并向列表中添加更多元素时,@MatthewTodd val 似乎确实等于列表中的最后一个元素。在旁注中,print [x for x in [0, 1, -1] if x>0] 打印 [1]。也就是说,它在 python 3 中不起作用。 【参考方案1】:

在 Python 2.x 中,定义在列表推导中的变量会泄漏到它们的封闭范围内,所以是的,val 将始终绑定到在列表推导期间绑定到 x 的最后一个值(只要理解是非空的,因此是“真实的”列表)。

但是,在 Python 3.x 中,情况不再如此:

>>> x = 'foo'
>>> if [x for x in [0, 1, -1] if x > 0]:
...     val = x
... 
>>> val
'foo'

这种行为(几乎没有)记录在案here:

在 Python 2.3 及更高版本中,列表解析将其包含的每个 for 的控制变量“泄漏”到包含范围内。但是,这种行为已被弃用,并且依赖它在 Python 3 中不起作用。

...随着 Python 3.x 中的更改记录在 here:

[...] 请注意,列表推导具有不同的语义:它们更接近于 list() 构造函数内的生成器表达式的语法糖,特别是循环控制变量不再是泄漏到周围的范围内。

看起来 2.x 的行为并不是任何人特别引以为豪的事情,事实上 Guido van Rossum 在blog post 中将其称为“Python 的“肮脏小秘密之一”。

【讨论】:

以上是关于列表推导中定义的变量是不是会泄漏到封闭范围内? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

Python2中的列表推导式存在变量泄漏问题,在Python3中不存在

JavaScript:闭包是不是可以通过值而不是像 PHP 中的引用来访问封闭范围内的变量?

Python 2.7 列表理解泄漏变量名 [重复]

无法引用封闭范围中定义的非最终局部变量按钮,随机方法错误

需要一个任意 PHP 文件,而不会将变量泄漏到作用域中

JavaScript中的“闭包”