Understanding Python generators
main| before gen.send(None)
foo | in foo
main| after 1 = gen.send(None)
main| yielded 1
main| before gen.send(10)
bar | in bar 10
main| after 2 = gen.send(10)
main| yielded 2
main| before gen.send(20)
bar | got x = 20
main| after 3 = gen.send(20)
main| yielded 3
main| before gen.send(30)
bar | got y = 30
bar | leaving bar
foo | foo got back 50
main| after 4 = gen.send(30)
main| yielded 4
main| before gen.send(40)
# https://eev.ee/blog/2016/07/31/python-faq-why-should-i-use-python-3/#yield-from
# https://jeffknupp.com/blog/2013/04/07/improve-your-python-yield-and-generators-explained/
# `yield`
# - pauses generator (saves its state) on the current line of code
# - returns yielded value (and control) to the caller
# - receives another `somevalue` from the caller via generator.send(somevalue)
# `yield from`
# - yields an entire sequence
# - can also take another generator or other lazy iterable, and it’ll
# pause the current generator until the given one has been exhausted
# - takes care of passing values back into the generator via .send() or .throw()
# what about .throw()?
# http://stackoverflow.com/a/11487070/6762004
def foo():
print("foo | in foo")
a = yield 1
b = yield from bar(a)
print("foo | foo got back", b)
yield 4
def bar(a):
print("bar | in bar", a)
x = yield 2
print("bar | got x =", x)
y = yield 3
print("bar | got y =", y)
print("bar | leaving bar")
return x + y
gen = foo()
val = None
while True:
try:
print('main| before gen.send(%s)' % val)
newval = gen.send(val)
print('main| after {0} = gen.send({1})'.format(newval, val))
except StopIteration:
break
print("main| yielded", newval)
val = newval * 10