Generators

WIP post

Generators in python are often sited as one of the useful things to learn, though people leave out a very interesting aspect though, the send method, but more on that later…

Basics

How to create generators:

Way #1

Implement the __next__ method on a class

class MyGenerator:
    def __init__(self):
        self.inner_list = [1, 2, 3]

    def __next__(self):
        try:
            return self.inner_list.pop(0)
        except IndexError:
            return None
Way #2

Using yield in a function

def my_gen():
    list_of_i = [0, 1]
    for i in list_of_i:
        yield i
Way #3

Generator comprehension can be created in a very similar way to list comprehension just swapping the outer [...] brackets for (...) brackets

gen_comp = (str(i) for i in range(10))

using generators

my_gen.__next__()

next(my_gen)

for i in my_gen

def my_gen():
    list_of_i = [0, 1]
    for i in list_of_i:
        yield i

x = my_gen()

print('First Call:', x.__next__())
print('Second Call:', next(x))
try:
    print('Third Call (will fail)')
    next(x)
except StopIteration:
    print('Catch StopIteration error')

returns:

First Call: 0
Second Call: 1
Third Call (will fail)
Catch StopIteration error

Lets break down what’s happening there…

Pros & Cons

The Send Method

yield is more that just magic pixie dust to sprinkle on return’s to make them better in some ways though!

Something that is often left out of the explanation of yield is that not only is it a way to exit from a “function”, it’s also an entrypoint!

Checkout this example:

def my_gen():
    list_of_i = [0, 1]
    y = 'will be changed'
    for i in list_of_i:
        y = yield i
        print(f'After yield, when i={i}, y={y} (type:{type(y)})')

x = my_gen()

print('First Call:', next(x))
print('Second Call:', x.send('new_y_value'))
try:
    print('Third Call (will fail)')
    next(x)
except StopIteration:
    print('Catch StopIteration error')

which returns:

First Call: 0
After yield, when i=0, y=new_y_value (type:<class 'str'>)
Second Call: 1
Third Call (will fail)
After yield, when i=1, y=None (type:<class 'NoneType'>)
Catch StopIteration error

Lets break down what’s happening there…

Yield From

yield from