[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
(http://golang.org/).
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:
<block>
else:
<block>
expands as:
_it = coiter(coiterable)
while True:
try:
val = cocall conext(_it)
except StopCoIteration:
break
<block>
else:
<block>
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()
sched.add(consumer(ch))
sched.add(producer(ch))
sched.run()
Thoughts?
- Jacob
More information about the Python-ideas
mailing list