Generators

def gen_char_from_string(text):
    i = 0
    while i < len(text):
        yield text[i]
        i += 1


gen = gen_char_from_string("one")
try:
    i = 0
    while True:
        ch = next(gen)
        print(f"{i}: {ch}")
        i += 1
except StopIteration:
    print("ended by exception")
0: o
1: n
2: e
ended by exception
def gen_char_from_string(text):
    for ch in text:
        yield ch


characters = [ch for ch in gen_char_from_string("two")]
print(f"result as list: {characters}")
result as list: ['t', 'w', 'o']
def gen_infinite(text):
    pos = 0
    while True:
        yield text[pos]
        pos = (pos + 1) % len(text)


for (i, ch) in enumerate(gen_infinite("three")):
    if i > 9:
        break
    print(i, ch)
0 t
1 h
2 r
3 e
4 e
5 t
6 h
7 r
8 e
9 e
def gen_combinations(left, right):
    for left_item in left:
        for right_item in right:
            yield (left_item, right_item)


for pair in gen_combinations("abc", [1, 2, 3]):
    print(pair)
('a', 1)
('a', 2)
('a', 3)
('b', 1)
('b', 2)
('b', 3)
('c', 1)
('c', 2)
('c', 3)
def gen_upper_lower(text):
    lower = True
    i = 0
    while i < len(text):
        result = text[i]
        i += 1
        temp = result.lower() if lower else result.upper()
        lower = (yield temp)


vowels = "aeiou"
generator = gen_upper_lower("abcdefg")
ch = next(generator)
while True:
    print(ch)
    flag = ch in vowels
    try:
        ch = generator.send(flag)
    except StopIteration:
        break
a
b
C
D
E
F
G

Exercises

  1. Write a generator that produces items alternately from two lists.
  2. Write a generator that produces the average of the most recent N items in a list (sliding window average).
  3. Use yield from to generate a flat list from arbitrary nested lists.
  4. Explain why gen/send_buggy.py doesn't work.
def gen_upper_lower(text):
    lower = True
    i = 0
    while i < len(text):
        result = text[i]
        i += 1
        temp = result.lower() if lower else result.upper()
        lower = (yield temp)


vowels = "aeiou"
generator = gen_upper_lower("abcdefg")
for ch in generator:
    print(ch)
    flag = ch in vowels
    ch = generator.send(flag)
a
C
E
G
Traceback (most recent call last):
  File "/Users/gvwilson/sim/intro/send_buggy.py", line 16, in <module>
    ch = generator.send(flag)
StopIteration