当前位置: 首页 > 面试题库 >

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

洪弘毅
2023-03-14
问题内容

如果我使用列表推导方法执行操作,它将写入局部变量:

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在写关于统一内置在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理解 也不会这样做。这主要是因为dict理解是从Python 3向后移植的,因此已经在其中进行了修复。



 类似资料:
  • 对于我的程序,我要编写一个程序,它接受2到10之间的行数。生成n行的乘法三角形。每行包含的条目不超过其行大小。这一点我没有问题。但是,在用户将数字0输入到我的问题“请输入要打印的行数:”之后,应该终止循环并打印“感谢您使用此程序!”我用了一个DO。。。WHILE循环以确定用户是否希望继续。在我的循环中,我将用户想要打印的数字声明为int num。我的循环应该持续到num

  • 请问上述代码的第70行换成第71行注释的内容时,为什么会造成死循环。 题目: https://www.acwing.com/problem/content/174/

  • 我们一直在学习循环和嵌套循环。 我的问题; 为什么增量结束后,内部for循环中变量的值会自动重置?但是,在外部for循环中,变量保持其值。 例如: 在这种情况下,程序运行10次,同时将i和count增量增加到18,然后返回到6?每次。。。有人能解释一下为什么会这样吗?

  • 问题内容: 我在程序中看到了与程序中此特定循环相关的不同行为,但我不确定我为什么理解它的行为方式。 的输出是 的输出是 我去网上看了以下内容 在切片上进行测距时,每次迭代都会返回两个值。第一个是索引,第二个是该索引处的元素的副本 它说一个副本,这是否意味着它返回了字符串的副本,但这实际上是指向变量的指针?在这种情况下,在循环结束时对will的任何引用都实际上引用了数组中的最后一个元素,例如?这是否

  • 问题内容: 我做了作业,无意间发现了算法速度方面的奇怪不一致。这是具有相同功能bur的2个版本的代码,但有1个区别:在第一个版本中,我使用3倍数组生成器来过滤某些数组,在第二个版本中,我使用1个for循环与3个if语句来执行相同的过滤器工作。 因此,这是第一个版本的代码: 这里是第二版的代码: 第1版的IPython输出: 对于第二版: 那么,为什么第一个版本比第二个版本快?我还使用filter(

  • 我写了这个简单的代码来获取一个double,并一直询问直到得到一个为止,但是当你给一个string时,它就变成了一个无限循环,我不知道为什么。为什么它会这样?