[Python-Dev] Re: anonymous blocks

Brett C. bac at OCF.Berkeley.EDU
Thu Apr 28 03:03:55 CEST 2005

Neil Schemenauer wrote:
> On Wed, Apr 27, 2005 at 03:58:14PM -0700, Guido van Rossum wrote:
>>Time to update the PEP; I'm pretty much settled on these semantics
> [I'm trying to do a bit of Guido channeling here.  I fear I may not
> be entirely successful.]
> The the __error__ method seems to simplify things a lot.  The
> purpose of the __error__ method is to notify the iterator that the
> loop has been exited in some unusual way (i.e. not via a
> StopIteration raised by the iterator itself).
> The translation of a block-statement could become:
>         itr = EXPR1
>         arg = None
>         while True:
>             try:
>                 VAR1 = next(itr, arg)
>             except StopIteration:
>                 break
>             try:
>                 arg = None
>                 BLOCK1
>             except Exception, exc:
>                 err = getattr(itr, '__error__', None)
>                 if err is None:
>                     raise exc
>                 err(exc)
> The translation of "continue EXPR2" would become:
>         arg = EXPR2
>         continue
> The translation of "break" inside a block-statement would
> become:
>         err = getattr(itr, '__error__', None)
>         if err is not None:
>             err(StopIteration())
>         break
> The translation of "return EXPR3" inside a block-statement would
> become:
>         err = getattr(itr, '__error__', None)
>         if err is not None:
>             err(StopIteration())
>         return EXPR3
> For generators, calling __error__ with a StopIteration instance
> would execute any 'finally' block.  Any other argument to __error__
> would get re-raised by the generator instance.
> You could then write:
>     def opened(filename):
>         fp = open(filename)
>         try:
>             yield fp
>         finally:
>             fp.close()
> and use it like this:
>     block opened(filename) as fp:
>         ....

Seems great to me.  Clean separation of when the block wants things to keep
going if it can and when it wants to let the generator it's all done.

> The main difference between 'for' and 'block' is that more iteration
> may happen after breaking or returning out of a 'for' loop.  An
> iterator used in a block statement is always used up before the
> block is exited.

This constant use of the phrase "used up" for these blocks is bugging me
slightly.  It isn't like the passed-in generator is having next() called on it
until it stops, it is just finishing up (or cleaning up, choose your favorite
term).  It may have had more iterations to go, but the block signaled it was
done and thus the generator got its chance to finish up and wipe pick up after

> Maybe __error__ should be called __break__ instead.

I like that.

> StopIteration
> is not really an error.  If it is called something like __break__,
> does it really need to accept an argument?  Of hand I can't think of
> what an iterator might do with an exception.

Could just make the default value be StopIteration.  Is there really a perk to
__break__ only raising StopIteration and not accepting an argument?

The real question of whether people would use the ability of raising other
exceptions passed in from the block.  If you view yield expressions as method
calls, then being able to call __break__ with other exceptions makes sense
since you might code up try/except statements within the generator and that
will care about what kind of exception gets raised.


More information about the Python-Dev mailing list