Step 5 - A runnable Example¶
Lets take a look at our current concept by using a runnable example.
def loop(coroutine):
"""Loop v1"""
step = 1
while True:
print("Loop step", step)
try:
next(coroutine)
step += 1
except StopIteration as e:
return e.value
from loop import loop
def generator_one():
print(generator_one.__name__, 1)
yield
print(generator_one.__name__, 2)
def generator_two():
print(generator_two.__name__, 1)
yield
print(generator_two.__name__, 2)
yield
print(generator_two.__name__, 3)
def chaining_generator():
print(chaining_generator.__name__, 1)
yield from generator_one()
print(chaining_generator.__name__, 2)
yield from generator_two()
print(chaining_generator.__name__, 3)
def main_generator():
print(main_generator.__name__, 1)
yield from chaining_generator()
print(main_generator.__name__, 2)
result = loop(main_generator())
print("Loop finished with result", result)
Output:
Loop step 1
main_generator 1
chaining_generator 1
generator_one 1
Loop step 2
generator_one 2
chaining_generator 2
generator_two 1
Loop step 3
generator_two 2
Loop step 4
generator_two 3
chaining_generator 3
main_generator 2
Loop finished with result None
As a sequence diagram:
sequenceDiagram participant l as loop participant mg as Main Generator participant cg as Chaining Generator participant g1 as Generator One participant g2 as Generator Two activate l activate l l->>mg: next deactivate l activate mg activate mg mg->>cg: yield from deactivate mg activate cg activate cg cg->>g1: yield from deactivate cg activate g1 activate g1 g1-->>l: yield deactivate g1 activate l l->>g1: next deactivate l activate g1 g1->>cg: return deactivate g1 deactivate g1 activate cg cg->>g2: yield from deactivate cg activate g2 activate g2 g2-->>l: yield deactivate g2 activate l l->>g2: next deactivate l activate g2 g2-->>l: yield deactivate g2 activate l l->>g2: next deactivate l activate g2 g2->>cg: return deactivate g2 deactivate g2 activate cg cg->>mg: return deactivate cg deactivate cg activate mg mg->>l: return deactivate mg deactivate mg deactivate l
Summary
We have learned so far:
yield
suspends execution of a coroutine.Using
yield from
suspends the execution back to the initial caller at the root - the loop.The loop resumes the execution where the last
yield
was executed.A loop is easiest to be implemented as a function that gets a single coroutine passed as argument. This coroutine may call other coroutines.