[Python-ideas] Possible PEP 380 tweak

Jacob Holm jh at improva.dk
Wed Oct 27 18:53:07 CEST 2010

On 2010-10-26 18:56, Guido van Rossum wrote:
> Now, if I may temporarily go into wild-and-crazy mode (this *is*
> python-ideas after all :-), we could invent some ad-hoc syntax for
> this pattern, e.g.:
>   for value in yield:
>     <use value>
>   return <result>
> IOW the special form:
>   for <var> in yield:
>     <body>
> would translate into:
>   try:
>     while True:
>       <var> = yield
>       <body>
>   except GeneratorExit:
>     pass
> If (and this is a big if) the
> while-True-yield-inside-try-except-GeneratorExit pattern somehow
> becomes popular we could reconsider this syntactic extension or some
> variant. (I have to add that the syntactic ice is a bit thin here,
> since "for <var> in (yield)" already has a meaning, and a totally
> different one of course. A variant could be "for <var> from yield" or
> some other abuse of keywords.

Hmm.  This got me thinking.  One thing I'd really like to see in python
is something like the "channel" object from the go language

Based on PEP 380 or Gregs new cofunctions PEP (or perhaps even without
any of them) it is possible to write a trampoline-based implementation
of a channel object with "send" and "next" methods that work as
expected.  One thing that is *not* possible (I think) is to make that
object iterable.  Your wild idea above gave me a similar wild idea of my
own.  An extension to the cofunctions PEP that would make that possible.

1) Define a new "coiterator" protocol, consisting of a new special
method __conext__, and a new StopCoIteration exception that the regular
StopIteration inherits from.  __conext__ should be a generator that
yields as many times as necessary, then either raises StopCoIteration or
returns a result (possibly by raising a StopIteration with a value).
Add a new built-in "conext" cofunction that looks for a __conext__
method instead of a __next__ method.

2) Define a new "coiterable" protocol, consisting of a new special
method __coiter__.  __coiter__ is a regular function and should return
an object implementing the "coiterator" protocol.  Add a new built-in
"coiter" function that looks for a __coiter__ method instead of an
__iter__ method.   (We could also make this a cofunction but for now I
don't see the point).

3) Make sure that the for-loop in a cofunction:

   for val in coiterable:

expands as:

   _it = coiter(coiterable)
   while True:
           val = cocall conext(_it)
       except StopCoIteration:

Which is exactly the same as in a normal function, except for the use of
"coiter" and "cocall conext" instead of "iter" and "next", and the use
of StopCoIteration instead of StopIteration.

3a) Alternatively define a new syntax for "coiterating" that expands as
in 3 and whose use is an alternative indicator that this is a cofunction.

All this to make it possible to write a code like this:

def consumer(ch):
    for val in ch:
        cocall print(val) # XXX need a cocall somewhere

def producer(ch):
    for val in range(10):
        cocall ch.send(val)

def main()
    sched = scheduler()
    ch = channel()


- Jacob

More information about the Python-ideas mailing list