简体   繁体   中英

python StopIteration with Generators and lists

Following Jean's answer to my question on: Python converting strings in a list to numbers , I get a StopIteration exception when running the below minimal code.

primes and z2 are empty.

From googling I think I may need a while loop around the line in traceback but I'm not sure how to remedy?

Traceback:

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

Sample data in CSV file:

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

Minimal Code:

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)]

A list comprehension is not a generator or iterator itself. It will not stop when the expression side raises a StopIteration exception. The iterable that for ... in <iterable> loops over can use StopIteration to communicate to the for loop that iteration is done, but that doesn't extend to the rest of the construct.

If you need to get at most b number of elements from an iterator, use itertools.islice() :

primes = list(islice(z2, b))

It'll take up to b elements when iterated over, or less if there are not enough elements in z2 .

An earlier revision of the post you linked to tried to pad out the result with 0 values in case there were fewer than b elements by giving next() a default value. I'd have used itertools.repeat() and itertools.chain() to achieve this:

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

The chain(z2, repeat(0)) part will endlessly add 0 values after z2 is exhausted. islice() takes b elements from that sequence.

Demo:

>>> 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]

Note that you can't read from a CSV file twice in a row , not without rewinding the file object first. Your code is using csv.reader(csvfile) in two locations, but the csvfile file object does not go back to the start. Add csvfile.seek(0) before trying to read from it again.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM