python与生成器和列表的StopIteration

时间:2017-10-14 14:36:12

标签: python python-2.7 list exception generator

在Jean回答我的问题:Python converting strings in a list to numbers后,运行以下最小代码时出现StopIteration异常。

primesz2为空。

从谷歌搜索我觉得我可能需要在回溯线上绕一条线循环,但我不确定如何补救?

回溯:

File "factorise_v32.py", line 118, in factorise
    primes=[next(z2) for _ in xrange(b)]  
StopIteration  

CSV文件中的示例数据:

("2","3","5","7","11")

最小代码:

import csv

def factorise(N)
    ....
    z1=(int(x) for row in csv.reader(csvfile) for x in row)
    ....
    b=4 #b can be any positive integer
    z2=(int(x) for row in csv.reader(csvfile) for x in row)
    primes=[next(z2) for _ in xrange(b)]

1 个答案:

答案 0 :(得分:2)

列表推导不是生成器或迭代器本身。当表达式端引发StopIteration异常时,它不会停止。 for ... in <iterable>循环的 iterable 可以使用StopIteration与迭代完成的for循环进行通信,但不会扩展到其余部分构造

如果您需要从迭代器中获取最多 b个元素,请使用itertools.islice()

primes = list(islice(z2, b))

迭代时最多需要b个元素,如果z2中没有足够的元素,则会更少。

您链接到的帖子的早期版本尝试填充结果0值,以防少于b个元素通过提供next()一个默认值。我已经使用itertools.repeat()itertools.chain()来实现这一目标:

primes = list(islice(chain(z2, repeat(0)), b))

chain(z2, repeat(0))部分将在0耗尽后无限添加z2个值。 islice()从该序列中获取b个元素。

演示:

>>> from itertools import chain, repeat, islice
>>> z2 = iter([1, 2, 3])
>>> list(islice(z2, 5))  # up to 5
[1, 2, 3]
>>> z2 = iter([1, 2, 3])  # pad with zeros
>>> list(islice(chain(z2, repeat(0)), 5))
[1, 2, 3, 0, 0]

请注意,无法连续两次从CSV文件中读取,而不是先将文件对象重绕。您的代码在两个位置使用csv.reader(csvfile),但csvfile文件对象不会返回到开头。在尝试再次阅读之前添加csvfile.seek(0)