Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trouble understanding python generators [duplicate]

Tags:

I am new to generator in python. I have a simple enough code which I am playing with but I can not understand the output I am getting out of it. Here is my code :

def do_gen():     for i in range(3):         yield i  def incr_gen(y):     return y + 1  def print_gen(x):     for i in x:         print i  x = do_gen() y = (incr_gen(i) for i in x) print_gen(x) print_gen(y) 

I expected my output to be like this :

0  1  2  1  2  3 

But I am seeing only : 0 1 2

I do not understand this output. Can anyone please help me sort out my lack of understanding? Thanks in advance.

like image 334
Santanu C Avatar asked Apr 23 '14 16:04

Santanu C


People also ask

Can you copy a generator Python?

Python doesn't have any support for cloning generators.

Can a generator be called multiple times in Python?

A Python generator is a function that produces a sequence of results. It works by maintaining its local state, so that the function can resume again exactly where it left off when called subsequent times. Thus, you can think of a generator as something like a powerful iterator.

How do I identify a Python generator?

from types import GeneratorType;type(myobject, GeneratorType) will give you the proper result for objects of class 'generator'.

Are generators lazy in Python?

Generators are memory efficient since they only require memory for the one value they yield. Generators are lazy: they only yield values when explicitly asked.


1 Answers

Generators (like all iterables) can only be iterated over once. By the time print_gen(x) is done, so is x. Any further attempts to get new values from x will result in StopIteration being raised.

This works:

x = do_gen() y = (incr_gen(i) for i in do_gen()) print_gen(x) print_gen(y) 

as that creates two separate independent generators. In your version, the generator expression you assigned to y expects x to yield more values.

It is easier to see that the x generator is shared with y when you use the next() function on them in turn:

>>> def do_gen(): ...     for i in range(3): ...         yield i ...  >>> def incr_gen(y): ...     return y + 1 ...  >>> x = do_gen() >>> y = (incr_gen(i) for i in x) >>> next(x)  # first value for the range 0 >>> next(y)  # second value from the range, plus 1 2 >>> next(x)  # third value from the range 2 >>> next(y)  # no more values available, generator done Traceback (most recent call last):   File "<stdin>", line 1, in <module> StopIteration 

Note the StopIteration raised by next(y) as well here.

like image 118
Martijn Pieters Avatar answered Oct 07 '22 19:10

Martijn Pieters