Skip to content

Instantly share code, notes, and snippets.

@kenichi-shibata
Last active April 14, 2018 10:35
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kenichi-shibata/7dd7b325f399f64a5a5676254706d6bf to your computer and use it in GitHub Desktop.
Save kenichi-shibata/7dd7b325f399f64a5a5676254706d6bf to your computer and use it in GitHub Desktop.
Python Generators Explained

Python Generators

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

Signing a generator to a varialble will automatically create .next() 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 None
1
>>> bangbang.__next__()
i got None
2
>>> next(bangbang)
i got None
3
>>> bangbang.__next__()
i got None
4

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


>>> next(bangbang)
i got None
5

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


>>> bangbang.send('yo')
i got yo
6
>>> bangbang.send('yo yo yo')
i got yo yo yo
7

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 None
i got None
i 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 test
Exception: 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 you 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 None
1>>> bangbang.__next__()
i got None
2>>> bangbang.__next__()
i got None
3>>> bangbang.__next__()
i got None
4>>> 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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment