为什么列表推导式会写入循环变量,而生成器却不会? [复制]

2024-04-08

如果我对列表推导式执行某些操作,它会写入局部变量:

i = 0
test = any([i == 2 for i in xrange(10)])
print i

这会打印“9”。但是,如果我使用生成器,它不会写入局部变量:

i = 0
test = any(i == 2 for i in xrange(10))
print i

这会打印“0”。

这种差异有什么充分的理由吗?这是一个设计决策,还是只是生成器和列表推导式实现方式的随机副产品?就我个人而言,如果列表推导式不写入局部变量,对我来说似乎更好。


Python 的创建者 Guido van Rossum 在写到生成器表达式 http://python-history.blogspot.de/2010/06/from-list-comprehensions-to-generator.html统一内置于 Python 3 中:(强调我的)

我们还在 Python 3 中进行了另一项更改,以改进列表推导式和生成器表达式之间的等效性。在 Python 2 中,列表推导式将循环控制变量“泄漏”到周围的作用域中:

x = 'before'
a = [x for x in 1, 2, 3]
print x # this prints '3', not 'before'

这是列表推导式最初实现的产物;多年来,它一直是 Python 的“肮脏的小秘密”之一。它最初是一种有意的妥协,目的是使列表推导式快速得令人眼花缭乱,虽然这对于初学者来说不是常见的陷阱,但它偶尔确实会刺痛人们。对于生成器表达式,我们无法这样做。生成器表达式是使用生成器实现的,生成器的执行需要单独的执行框架。因此,生成器表达式(特别是当它们迭代短序列时)的效率低于列表推导式。

然而,在 Python 3 中,我们决定使用与生成器表达式相同的实现策略来修复列表推导式的“肮脏的小秘密”。因此,在 Python 3 中,上面的示例(修改为使用 print(x) :-) 将打印 'before',证明列表推导式中的 'x' 暂时隐藏但不会覆盖周围的 'x'范围。

所以在 Python 3 中你不会再看到这种情况发生了。

有趣的是,字典理解在 Python 2 中也不这样做;这主要是因为 dict 推导式是从 Python 3 向后移植的,因此已经在其中进行了修复。

还有一些其他问题也涉及该主题,但我相信您在搜索该主题时已经看到了这些问题,对吗? ;)

  • 即使在理解范围之后,Python 列表理解也会重新绑定名称。这是正确的吗? https://stackoverflow.com/questions/4198906/python-list-comprehension-rebind-names-even-after-scope-of-comprehension-is-thi
  • 为什么操作完成后可以访问列表理解变量? https://stackoverflow.com/questions/16612575/why-the-list-comprehension-variable-is-accessible-after-the-operation-is-done
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么列表推导式会写入循环变量,而生成器却不会? [复制] 的相关文章

随机推荐