[Python-Dev] Re: anonymous blocks

Brett C. bac at OCF.Berkeley.EDU
Mon Apr 25 04:23:59 CEST 2005


Guido van Rossum wrote:
[SNIP]
> Now let me propose a strawman for the translation of the latter into
> existing semantics. Let's take the generic case:
> 
>     with VAR = EXPR:
>         BODY
> 
> This would translate to the following code:
[SNIP]
> 
>     it = EXPR
>     err = None
>     while True:
>         try:
>             VAR = it.next(err)
>         except StopIteration:
>             break
>         try:
>             err = None
>             BODY
>         except Exception, err: # Pretend "except Exception:" == "except:"
>             pass
> 
> but for backwards compatibility with the existing argument-less next()
> API I'm introducing a new iterator API next_ex() which takes an
> exception argument.

Can I suggest the name next_exc() instead?  Everything in the sys module uses
"exc" as the abbreviation for "exception".  I realize you might be suggesting
using the "ex" as the suffix because of the use of that as the suffix in the C
API for an extended API, but that usage is not prominent in the stdlib.

Also, would this change in Python 3000 so that both next_ex() and next() are
merged into a single method?

As for an opinion of the need of 'with', I am on the fence, leaning towards
liking it.  To make sure I am understanding the use case, it is to help
encapsulate typical resource management with proper cleanup in another function
instead of having to constantly pasting in boilerplate into your code, right?
So the hope is to be able to create factory functions, typically implemented as
a generator, that encapsulate the obtaining, temporary lending out, and cleanup
of a resource?

Is there some other use that I am totally missing that is obvious?

>  If that argument is None, it should behave just
> like next().  Otherwise, if the iterator is a generator, this will
> raised that exception in the generator's frame (at the point of the
> suspended yield).  If the iterator is something else, the something
> else is free to do whatever it likes; if it doesn't want to do
> anything, it can just re-raise the exception.
> 
> Also note that, unlike the for-loop translation, this does *not*
> invoke iter() on the result of EXPR; that's debatable but given that
> the most common use case should not be an alternate looping syntax
> (even though it *is* technically a loop) but a more general "macro
> statement expansion", I think we can expect EXPR to produce a value
> that is already an iterator (rather than merely an interable).
> 
> Finally, I think it would be cool if the generator could trap
> occurrences of break, continue and return occurring in BODY.  We could
> introduce a new class of exceptions for these, named ControlFlow, and
> (only in the body of a with statement), break would raise BreakFlow,
> continue would raise ContinueFlow, and return EXPR would raise
> ReturnFlow(EXPR) (EXPR defaulting to None of course).
> 
> So a block could return a value to the generator using a return
> statement; the generator can catch this by catching ReturnFlow.
> (Syntactic sugar could be "VAR = yield ..." like in Ruby.)
> 
> With a little extra magic we could also get the behavior that if the
> generator doesn't handle ControlFlow exceptions but re-raises them,
> they would affect the code containing the with statement; this means
> that the generator can decide whether return, break and continue are
> handled locally or passed through to the containing block.
> 

Honestly, I am not very comfortable with this magical meaning of 'break',
'continue', and 'return' in a 'with' block.  I realize 'return' already has
special meaning in an generator, but I don't think that is really needed
either.  It leads to this odd dichotomy where a non-exception-related statement
directly triggers an exception in other code.  It seems like code doing
something behind my back; "remember, it looks like a 'continue', but it really
is a method call with a specific exception instance.  Surprise!"

Personally, what I would rather see, is to have next_ex(), for a generator,
check if the argument is a subclass of Exception.  If it is, raise it as such.
 If not, have the 'yield' statement return the passed-in argument.  This use of
it would make sense for using the next_ex() name.

Then again I guess having exceptions triggering a method call instead of
hitting an 'except' statement is already kind of "surprise" semantics anyway.
=)  Still, I would like to minimize the surprises that we could spring.

And before anyone decries the fact that this might confuse a newbie (which
seems to happen with every advanced feature ever dreamed up), remember this
will not be meant for a newbie but for someone who has experience in Python and
iterators at the minimum, and hopefully with generators.  Not exactly meant for
someone for which raw_input() still holds a "wow" factor for.  =)

> Note that EXPR doesn't have to return a generator; it could be any
> object that implements next() and next_ex().  (We could also require
> next_ex() or even next() with an argument; perhaps this is better.)
> 

Yes, that requirement would be good.  Will make sure people don't try to use an
iterator with the 'with' statement that has not been designed properly for use
within the 'with'.  And the precedence of requiring an API is set by 'for'
since it needs to be an iterable or define __getitem__() as it is.

-Brett


More information about the Python-Dev mailing list