send() to a generator in a "for" loop with continue(val)??

Michele Simionato michele.simionato at gmail.com
Sun Apr 19 03:08:50 EDT 2009


On Apr 19, 8:09 am, Michele Simionato wrote:
> Coroutines instead could have been implemented as
> a library, without requiring any syntax change.

Here is a proof of principle, just to make clearer
what I have in mind. Suppose you have the following
library:

$ cat coroutine.py
from abc import abstractmethod

class Coroutine(object):
    @abstractmethod
    def main(self):
        yield

    def send(self, value):
        if not hasattr(self, '_it'): # first call
            self._it = self.main()
        self._value = value
        return self._it.next()

    def recv(self):
        return self._value

    def close(self):
        self._it.close()
        del self._it
        del self._value

Then you could write coroutines as follows:

$ cat coroutine_example.py
from coroutine import Coroutine

class C(Coroutine):
    def main(self):
        while True:
            val = self.recv()
            if not isinstance(val, int):
                raise TypeError('Not an integer: %r' % val)
            if val % 2 == 0:
                yield 'even'
            else:
                yield 'odd'

if __name__ == '__main__':
    c = C()
    for val in (1, 2, 'x', 3):
        try:
            out = c.send(val)
        except StopIteration:
            break
        except Exception, e:
            print e
        else:
            print out

This is not really worse of what we do today with the yield
expression:

$ cat coroutine_today.py
def coroutine():
    val = yield
    while True:
        if not isinstance(val, int):
            raise TypeError('Not an integer: %r' % val)
        if val % 2 == 0:
            val = yield 'even'
        else:
            val = yield 'odd'

if __name__ == '__main__':
    c = coroutine()
    c.next()
    for val in (1, 2, 'x', 3):
        try:
            out = c.send(val)
        except StopIteration:
            break
        except Exception, e:
            print e
        else:
            print out

Actually it is clearer, since it avoids common mistakes
such as forgetting the ``val = yield`` line in the coroutine
function and the ``c.next`` line right after instantiation
of the coroutine object, which are needed to initialize
the coroutine correctly.



More information about the Python-list mailing list