Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get the n next values of a generator in a list (python)

I have made a generator to read a file word by word and it works nicely.

def word_reader(file):     for line in open(file):         for p in line.split():             yield p  reader = word_reader('txtfile') next(reader) 

What is the easiest way of getting the n next values in a list?

like image 575
Peter Smit Avatar asked Nov 11 '10 08:11

Peter Smit


People also ask

How do I find the next value of a generator?

To get values from the generator object, call the next() method on the generator object or loop through the generator object.

How do you get the next element while cycling through a list in Python?

Get Next Element in Python List using next() First of all, convert the list into the iterative cycle using cycle() method. For that, you have to import the cycle from itertools which come preinstalled with Python. Then use the next() method to find the next element in the Python iterator.

How many times can you iterate all the way through a generator Python?

This is because generators, like all iterators, can be exhausted. Unless your generator is infinite, you can iterate through it one time only.

How do you find the first n elements in a list?

To access the first n elements from a list, we can use the slicing syntax [ ] by passing a 0:n as an arguments to it . 0 is the start index (it is inculded). n is end index (it is excluded).


2 Answers

Use itertools.islice:

list(itertools.islice(it, n)) 
like image 51
Ignacio Vazquez-Abrams Avatar answered Oct 04 '22 06:10

Ignacio Vazquez-Abrams


TL;DR: Use itertools.islice.

Originally I wrote another answer, that turned out to be a bad idea:

[next(it) for _ in range(n)] 

This crashes when it yields less than n values, and this behaviour depends on subtle issues, so people reading such code are unlikely to understand it's precise semantics.

What happens if next(it) was exhausted and raises StopIteration?

(i.e. when it had less than n values to yield)

When I wrote the above line a couple years ago, I probably thought a StopIteration will have the clever side effect of cleanly terminating the list comprehension. But no, the whole comprehension will crash passing the StopIteration upwards. (It'd exit cleanly only if the exception originated from the range(n) iterator.)

Which is probably not the behavior you want.

But it gets worse. The following is supposed to be equivalent to the list comprehension (especially on Python 3):

list(next(it) for _ in range(n)) 

It isn't. The inner part is shorthand for a generator function; list() knows it's done when it raises StopIteration anywhere.
=> This version copes safely when there aren't n values and returns a shorter list. (Like itertools.islice().)

[Executions on: 2.7, 3.4]

But that's too going to change! The fact a generator silently exits when any code inside it raises StopIteration is a known wart, addressed by PEP 479. From Python 3.7 (or 3.5 with a future import) that's going to cause a RuntimeError instead of cleanly finishing the generator. I.e. it'll become similar to the list comprehension's behaviour. (Tested on a recent HEAD build)

like image 33
Beni Cherniavsky-Paskin Avatar answered Oct 04 '22 04:10

Beni Cherniavsky-Paskin