This code is practical mainly in the trivial sense that it runs to
completion.

# -*- coding: utf-8 -*-
"""
Created on Sun Jan  3 13:51:20 2016

@author: kurner
"""
import itertools

def assemble():
    drv = yield None
    drv.result = 1
    drv = yield drv
    drv.result += 1
    drv.name = "Alvin"
    drv = yield drv
    drv.result += 1
    drv.color = "Red"
    drv = yield drv
    drv.result += 1
    drv.age = 100
    return drv

class Driver:

    def __init__(self, g):
        self.g = g
        self.g.send(None) # primed
        self.counter = 1

    def go(self):
        while True:
            try:
                self.counter *= 10
                self = self.g.send(self)
            except StopIteration as exc:
                return exc.args[0].__dict__

d = Driver(assemble())
r = d.go()
print(r)

Console output:

{'name': 'Alvin', 'color': 'Red', 'age': 100, 'counter': 10000, 'g':
<generator object assemble at 0x110078af0>, 'result': 4}

The tractor classes I posted earlier should more properly by referred to as
co-routines, as they were driven by a "tick" loop.  Python itself is
growing more powerful in this area.

What stands out about assemble() is it has yields, so is clearly a
generator, but also it returns, and the StopIteration value is not only
recoverable, but what we expect more generally from a 'yield from'.

What assemble returns is a thing that keeps pushing the coroutine with a
send(), actually sending itself, meaning it grows attributes from both
inside and outside the coroutine.  I dump the state of said "thing" as the
end result.

One starts to see the relevance to concurrency when imagining many
coroutines such as assemble() that keep relinquishing control while holding
their place, each advancing as driven to do so by a "driver" (task) that
whips in on.

Kirby
_______________________________________________
Edu-sig mailing list
Edu-sig@python.org
https://mail.python.org/mailman/listinfo/edu-sig

Reply via email to