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