Alex-Just
1/22/2017 - 10:20 AM

Understanding Python generators

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