在生成器中使用continue

1 投票
2 回答
1381 浏览
提问于 2025-04-18 18:17

我想用continue这个功能来跳过一些不符合特定条件的生成项。

如果我直接打印x,我会得到完整的输出:

>>> w = [1,4,6,10]
>>> w2 = ((2 * x) for x in w)
>>> for x in w2: print x
...
2
8
12
20

但是,当我试图用continue来不打印8的时候,输出却变成了空白。

>>> for x in w2:
...     if x == 8: continue
...     print x
...
>>>

我想在第二次循环中得到2、12和20的输出。我该怎么做才能得到想要的结果呢?

2 个回答

1
>>> w=[1,4,6,10]
>>> w2=((2 * x) for x in w)
>>> for x in w2:
...     print x
... 
2
8
12
20
>>> w2=((2 * x) for x in w)
>>> for x in w2:
...     if x == 8: continue
...     print x
... 
2
12
20

给出正确的结果?!

你每次在使用 for 循环之前,都需要用 w2=((2 * x) for x in w) 这段代码(如果你是在终端上,就像 enrico.bacis 说的那样)。最好还是使用一个集成开发环境(IDE),像 IDLE 也可以。如果你还是想用命令行,那就最好写一个 function

2

生成器和列表不一样,生成器是在需要的时候才生成元素,而且这些元素不会一直保存在内存里。一旦你把所有的元素都用完了,再次尝试遍历它们时,生成器就不会再输出任何东西,因为它已经被用过了。

很可能你在第一次循环中就已经用掉了生成器,所以当你再尝试遍历它时,它是空的。你可以试着用 print list(w2) 来检查一下你的元素是否还在。

示例

我们来定义一个函数,从一个可迭代对象中打印元素,直到遇到某个值:

def printuntil(iterable, stopval):
    for item in iterable:
       print item
       if item == stopval:
           break

现在我们用一个列表试两次:

>>> vals = [2 * x for x in range(3)]
>>> printuntil(vals, 2)
0
2
>>> printuntil(vals, 4)
0
2
4

一切看起来都没问题,我们再用生成器试一次:

>>> vals = (2 * x for x in range(3))
>>> printuntil(vals, 2)
0
2
>>> printuntil(vals, 4)
4

如你所见,数字 02 已经被用掉了,所以第二次调用只打印了第一个还没被用掉的元素:4。所以如果你想多次遍历一个可迭代对象,最好用列表。

复制生成器

你可以在使用生成器之前用 itertools.tee 来复制它,这样就能享受到不把元素存到列表里的好处。

>>> vals = (2 * x for x in range(5))
>>> from itertools import tee
>>> vals, valscopy = tee(vals)
>>> printuntil(vals, 2)
0
2
>>> printuntil(valscopy, 4)
0
2
4

这样做会节省内存,但在性能上可能不太高效,因为每次都需要生成元素。

撰写回答