[Python-Dev] PEP 342 suggestion: start(), __call__() and unwind_call() methods
Nick Coghlan
ncoghlan at gmail.com
Sun Oct 9 03:10:56 CEST 2005
Guido van Rossum wrote:
>>This change would make a huge difference to the practical usability of these
>>generator-based tasks. I think they're much less likely to catch on if you
>>have to write "raise StopIteration( Result )" (or "_return( Result )") all the
>>time.
>>
>>[1] a.k.a. coroutines, which i don't think is an accurate name, anymore.
>
>
> Before we do this I'd like to see you show some programming examples
> that show how this would be used. I'm having a hard time understanding
> where you would need this but I realize I haven't used this paradigm
> enough to have a good feel for it, so I'm open for examples.
>
> At least this makes more sense than mapping "return X" into "yield X;
> return" as someone previously proposed. :)
It would be handy when the generators are being used as true pseudothreads
with a scheduler like the one I posted earlier in this discussion. It allows
these pseudothreads to "call" each other by yielding the call as a lambda or
partial function application that produces a zero-argument callable. The
called pseudothread can then yield as many times as it wants (either making
its own calls, or just being a well-behaved member of a cooperatively MT
environment), and then finally returning the value that the original caller
requested.
Using 'return' for this is actually a nice idea, and if we ever do make it
legal to use 'return' in generators, these are the semantics it should have.
However, I'm not sure its something we should be adding *right now* as part of
PEP 342 - writing "raise StopIteration" and "raise StopIteration(result)", and
saying that a generator includes an implied "raise StopIteration" after its
last line of code really isn't that difficult to understand, and is completely
explicit about what is going on.
My basic concern is that I think replacing "raise StopIteration" with "return"
and "raise StopIteration(EXPR)" with "return EXPR" would actually make such
code easier to write at the expense of making it harder to *read*, because the
fact that an exception is being raised is obscured. Consider the following two
code snippets:
def function():
try:
return
except StopIteration:
print "We never get here."
def generator():
yield
try:
return
except StopIteration:
print "But we would get here!"
So, instead of having "return" automatically map to "raise StopIteration"
inside generators, I'd like to suggest we keep it illegal to use "return"
inside a generator, and instead add a new attribute "result" to StopIteration
instances such that the following three conditions hold:
# Result is None if there is no argument to StopIteration
try:
raise StopIteration
except StopIteration, ex:
assert ex.result is None
# Result is the argument if there is exactly one argument
try:
raise StopIteration(expr)
except StopIteration, ex:
assert ex.result == ex.args[0]
# Result is the argument tuple if there are multiple arguments
try:
raise StopIteration(expr1, expr2)
except StopIteration, ex:
assert ex.result == ex.args
This precisely parallels the behaviour of return statements:
return # Call returns None
return expr # Call returns expr
return expr1, expr2 # Call returns (expr1, expr2)
Cheers,
Nick.
--
Nick Coghlan | ncoghlan at gmail.com | Brisbane, Australia
---------------------------------------------------------------
http://boredomandlaziness.blogspot.com
More information about the Python-Dev
mailing list