[Python-Dev] Coroutines and PEP 380

Mark Shannon mark at hotpy.org
Tue Jan 17 23:03:45 CET 2012


Hi all.

Lets start controversially: I don't like PEP 380, I think it's a kludge.

I think that CPython should have proper coroutines, rather than add more 
bits and pieces to generators in an attempt to make them more like 
coroutines.

I have mentioned this before, but this time I have done something about 
it :)

I have a working, portable, (asymmetric) coroutine implementation here:

https://bitbucket.org/markshannon/hotpy_coroutines

Its all standard C, no messing with the C stack, just using standard 
techniques to convert recursion to iteration
(in the VM not at the Python level) and a revised internal calling 
convention to make CPython stackless:

https://bitbucket.org/markshannon/hotpy_stackless

Then I've added a Coroutine class and fiddled with the implementation of 
YIELD_VALUE to support it.

I think the stackless implementation is pretty solid, but the
coroutine stuff needs some refinement.
I've not tested it well (it passes the test suite, but I've added no new 
tests).
It is (surprisingly) a bit faster than tip (on my machine).
There are limitations: all calls must be Python-to-Python calls,
which rules out most __xxx__ methods. It might be worth special casing 
__iter__, but I've not done that yet.

To try it out:

 >>> import coroutine
To send a value to a coroutine:
 >>> co.send(val)
where co is a Coroutine()
To yield a value:
 >>> coroutine.co_yield(val)
send() is a method, co_yield is a function.

Here's a little program to demonstrate:

import coroutine

class Node:
     def __init__(self, l, item, r):
         self.l = l
         self.item = item
         self.r = r

def make_tree(n):
     if n == 0:
         return Node(None, n, None)
     else:
         return Node(make_tree(n-1), n, make_tree(n-1))

def walk_tree(t, f):
     if t is not None:
         walk_tree(t.l, f)
         f(t)
         walk_tree(t.r, f)

def yielder(t):
     coroutine.co_yield(t.item)

def tree_yielder(t):
     walk_tree(t, yielder)

co = coroutine.Coroutine(tree_yielder, (make_tree(2),))

while True:
     print(co.send(None))

Which will output:

0
1
0
2
0
1
0
None
Traceback (most recent call last):
   File "co_demo.py", line 30, in <module>
     print(co.send(None))
TypeError: can't send to a halted coroutine


Cheers,
Mark.


More information about the Python-Dev mailing list