Guido van Rossum wrote:
It seems that the same argument that explains why generators are so
good for defining iterators, also applies to the PEP 310 use case:
it's just much more natural to write

    def with_file(filename):
        f = open(filename)
        try:
            yield f
        finally:
            f.close()

than having to write a class with __entry__ and __exit__ and
__except__ methods (I've lost track of the exact proposal at this
point).

Indeed - the transaction example is very easy to write this way:

    def transaction():
        begin_transaction()
        try:
            yield None
        except:
            abort_transaction()
            raise
        else:
            commit_transaction()

> 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).

Not supporting iterables makes it harder to write a class which is inherently usable in a with block, though. The natural way to make iterable classes is to use 'yield' in the definition of __iter__ - if iter() is not called, then that trick can't be used.

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).

Perhaps 'continue' could be used to pass a value into the iterator, rather than 'return'? (I believe this has been suggested previously in the context of for loops)


This would permit 'return' to continue to mean breaking out of the containing function (as for other loops).

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.)

So, "VAR = yield x" would expand to something like:

    try:
        yield x
    except ReturnFlow, ex:
        VAR = ReturnFlow.value

?

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.

That seems a little bit _too_ magical - it would be nice if break and continue were defined to be local, and return to be non-local, as for the existing loop constructs. For other non-local control flow, application specific exceptions will still be available.


Regardless, the ControlFlow exceptions do seem like a very practical way of handling the underlying implementation.

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.)

With this restriction (i.e. requiring next_ex, next_exc, or Terry's suggested __next__), then the backward's compatible version would be simply your desired semantics, plus an attribute check to exclude old-style iterators:


     it = EXPR
     if not hasattr(it, "__next__"):
         raise TypeError("'with' block requires 2nd gen iterator API support")
     err = None
     while True:
         try:
             VAR = it.next(err)
         except StopIteration:
             break
         try:
             err = None
             BODY
         except Exception, err: # Pretend "except Exception:" == "except:"
             pass

The generator objects created by using yield would supply the new API, so would be usable immediately inside such 'with' blocks.

Cheers,
Nick.

--
Nick Coghlan   |   [EMAIL PROTECTED]   |   Brisbane, Australia
---------------------------------------------------------------
            http://boredomandlaziness.skystorm.net
_______________________________________________
Python-Dev mailing list
Python-Dev@python.org
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com

Reply via email to