[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