Python 列表推导覆盖值

19 投票
4 回答
2638 浏览
提问于 2025-04-16 09:17

看看下面这段代码,它展示了一个列表推导式:

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

当你在Python 2.6中运行这个代码示例时,它会输出99,但在Python 3.x中运行时,它会输出6。

为什么会改变这个行为呢?为什么在Python 3.x中输出是6呢?

4 个回答

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 中,这个问题已经解决,列表推导式不再泄露控制变量了)

7

是的,确实有原因。这个原因是他们不希望在列表推导式中使用的临时变量影响到外部的命名空间。所以这是一个有意的改变,因为现在列表推导式实际上是把一个生成器表达式传递给 list() 的一种简化写法。

参考链接:PEP3100

33

之前的行为是个错误,但因为有些代码依赖于这个错误,所以不容易修复。

在列表推导式中,变量 i 应该和外面那个 i 不一样。逻辑上,它应该有自己的作用域,也就是说它的作用范围只在列表推导式内部,因为它的值只在这里有意义。但是在 Python 2.x 中,由于实现上的一些细节,这个作用域比需要的要大,导致这个变量“泄漏”到了外面的作用域,从而产生了让人困惑的结果。

Python 3.0 刻意不向之前的版本兼容,所以他们借这个机会修复了这个不好的行为。

在 Python 2.3 及以后的版本中,列表推导式会把里面每个循环的控制变量“泄漏”到外面的作用域。不过,这种行为已经被弃用,依赖它在 Python 3.0 中是行不通的。

来源

撰写回答