paint-brush
Python Generators Explained! (Sort of)by@kenichishibata
2,541 reads
2,541 reads

Python Generators Explained! (Sort of)

by kenichiNovember 24th, 2017
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

Learn <a href="https://hackernoon.com/tagged/python" target="_blank">python</a> generators by example.

Company Mentioned

Mention Thumbnail
featured image - Python Generators Explained! (Sort of)
kenichi HackerNoon profile picture

Learn python generators by example.

As Iterators

Using generators (generator functions)

>>> def integers():    i = 1     while True:        yield i        i = i + 1>>> a = integers()>>> next(a)1>>> next(a)2>>> next(a)3>>> next(a)4>>> next(a)5>>>

Assigning a generator to a varialble will automatically create .__next__() or next(generator) method

This will allow you to iterate through the generator values

Converting to list

>>> def yrange(n):    i = 0    while i < n:        yield i        i += 1>>> y = yrange(5)>>> list(y)[0, 1, 2, 3, 4]>>> list(y)[]

You can convert a generator to a list however on the process it will lose its value and transfer it to the list.

>> y = yrange(5)>>> ylist = list(y)>>> ylist[0, 1, 2, 3, 4]>>> ylist[0, 1, 2, 3, 4]>>> list(y)[]

You may assign it to a variable to retain the list. Keep in mind it the original generator will be gone.

The power to send to generators

>>> def whizbang():    for i in range(10):        x = yield i         print('i got {}'.format(x))>>> bangbang = whizbang()>>> bangbang.__next__()0>>> next(bangbang)i got None1>>> bangbang.__next__()i got None2>>> next(bangbang)i got None3>>> bangbang.__next__()i got None4

next(generator) is the same as generator.__next__(). Similar to how vars(class) is the same as class.__dict__.

>>> next(bangbang)i got None5

Let’s start sending stuff. Generators have generator.send() method.

>>> bangbang.send('yo')i got yo6>>> bangbang.send('yo yo yo')i got yo yo yo7

In this case bangbang.send’s parameter is assigned to x. Since x = yield i, means x = yield send value and yield i

>>>  list(bangbang)i got Nonei got Nonei got None[8, 9]

converting to list is not going to work with .send()

>>> bangbang = whizbang()>>> next(bangbang)0>>> list(bangbang.send('test'))i got testException: TypeError: 'int' object is not iterable---------------------------------------------------------------------------TypeError                                 Traceback (most recent call last)<ipython-input-1-5e0978d85904> in <module>()----> 1 list(bangbang.send('test'))

TypeError: 'int' object is not iterable>>>

you will need to call next(generator) at least once before doing a generator.send()

>>> bangbang = whizbang()>>> bangbang.send('s')Exception: TypeError: can't send non-None value to a just-started generator---------------------------------------------------------------------------TypeError                                 Traceback (most recent call last)<ipython-input-1-10a417413dc0> in <module>()----> 1 bangbang.send('s')

TypeError: can't send non-None value to a just-started generator

Removing values on generator early

Cleaning the values inside a generator is useful. For example if your application run into unknownerror and that left your application on a dirty state instead of risk writing a wrong data you can just close the generator early.

>>> bangbang = whizbang()>>> bangbang<generator object whizbang at 0x7f6b1537b288>>>> bangbang.__next__<method-wrapper '__next__' of generator object at 0x7f6b1537b288>>>> bangbang.__next__()0>>> bangbang.__next__()i got None1>>> bangbang.__next__()i got None2>>> bangbang.__next__()i got None3>>> bangbang.__next__()i got None4>>> bangbang.close()>>> bangbang.__next__()Exception: StopIteration: ---------------------------------------------------------------------------StopIteration                             Traceback (most recent call last)<ipython-input-1-6f12368577ae> in <module>()----> 1 bangbang.__next__()

StopIteration:

As you see above bangbang should iterate until 10 however it stopped at 4 since we called bangbang.close()

Further reading