Python列表推导式覆盖值

19

请看下面的一段代码,它展示了一个列表推导式。

>>> i = 6
>>> s = [i * i for i in range(100)]
>>> print(i)

Python 2.6中执行该代码示例会打印99,但在Python 3.x中执行时会打印6

为什么更改了行为,并且在Python 3.x中输出为6

提前感谢您的回答!


2
哇,我很幸运在这里找到了它,如果我在自己的代码中遇到这个问题,我可能要找几周的错误。对于这个问题加一分,但 Python 扣一分 :( - Kos
类似的问题在这里:https://dev59.com/mW855IYBdhLWcg3wsWhq - viam0Zah
4个回答

33

旧的行为是一个错误,但是由于某些代码依赖它而不能轻易修复。

列表推导式中的变量i应该与顶层的i不同。从逻辑上讲,它应该具有自己的作用域,超出推导式范围而不会扩展到外面,因为它的值只在推导式中有意义。但在Python 2.x中,由于实现细节,作用域比必要的范围更大,导致变量“泄漏”到外部作用域,从而产生您看到的混乱结果。

Python 3.0故意不保持向后兼容以修复此不良行为。

在 Python 2.3 及后续版本中,列表推导式“泄漏”包含在其中的每个 for 的控制变量到包含范围中。然而,这种行为已被弃用,并且依赖它将无法在 Python 3.0 中工作。

来源


7
是的,有一个原因,那就是他们不想让列表推导式中的临时变量泄漏到外部命名空间。因此,这是一种故意的改变,这是列表推导现在成为将生成器表达式传递给list()的语法糖的结果。
参考:PEP3100

5

Mark Byers回答得非常好。

顺便提一下..
在Python 2.x中,如果你将括号改为圆括号(创建一个生成器表达式而不是列表推导式),你会发现控制变量并没有泄漏。

>>> i = 6
>>> s = (i for i in range(100))
>>> print i
6

对比。

>>> i = 6
>>> s = [i for i in range(100)]
>>> print i
99

(当然,在Python 3中,这个问题已经得到解决,列表推导不再泄露控制变量)

这是一个很好的观点。但是还应该注意到s现在也不包含列表,所以要获得期望的最终结果,必须执行list(s) - Keith

0

看起来对我来说是作用域的变化。

我在Python 2.6中确认了您的结果;它确实打印99,这是列表推导式中分配给i的最后一个值。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接