[Python-checkins] python/nondist/peps pep-0343.txt,1.3,1.4

gvanrossum@users.sourceforge.net gvanrossum at users.sourceforge.net
Sat May 14 07:02:31 CEST 2005

Update of /cvsroot/python/python/nondist/peps
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv16548

Modified Files:
Log Message:
Add a motivational section, remove tabs, add colons, and some very
minor edits.

Index: pep-0343.txt
RCS file: /cvsroot/python/python/nondist/peps/pep-0343.txt,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- pep-0343.txt	14 May 2005 04:02:10 -0000	1.3
+++ pep-0343.txt	14 May 2005 05:02:28 -0000	1.4
@@ -17,7 +17,103 @@
 Motivation and Summary
-    TBD.
+    PEP 340, Anonymous Block Statements, combined many powerful ideas:
+    using generators as block templates, adding exception handling and
+    finalization to generators, and more.  Besides praise it received
+    a lot of opposition from people who didn't like the fact that it
+    was, under the covers, a (optential) looping construct.  This
+    meant that break and continue in a block-statement would break or
+    continue the block-statement, even if it was used as a non-looping
+    resource management tool.
+    But the final blow came when I read Raymond Chen's rant about
+    flow-control macros[1].  Raymond argues convincingly that hiding
+    flow control in macros makes your code inscrutable, and I find
+    that his argument applies to Python as well as to C.  I realized
+    that PEP 340 templates can hide all sorts of control flow; for
+    example, its example 4 (auto_retry()) catches exceptions and
+    repeats the block up to three times.
+    However, the with-statement of PEP 310 does *not* hide control
+    flow, in my view: while a finally-suite temporarily suspends the
+    control flow, in the end, the control flow resumes as if the
+    finally-suite wasn't there at all.  Consider this:
+        with VAR = EXPR:
+            BLOCK1
+        BLOCK2
+    Here, just as if the first line was "if True" instead, we know
+    that if BLOCK1 completes without an exception, BLOCK2 will be
+    reached; and if BLOCK1 raises an exception or executes a
+    non-local goto (a break, continue or return), BLOCK2 is *not*
+    reached.  The magic added by the with-statement at the end doesn't
+    affect this.
+    (You may ask, what if a bug in the __exit__ method causes an
+    exception?  Then all is lost -- but this is no worse than with
+    other exceptions; the nature of exceptions is that they can happen
+    *anywhere*, and you just have to live with that.  Even if you
+    write bug-free code, a KeyboardInterrupt exception can still cause
+    it to exit between any two virtual machine opcodes.)
+    This argument almost led me to endorse PEP 310, but I had one idea
+    left from the PEP 340 euphoria that I wasn't ready to drop: using
+    generators as "templates" for abstractions like acquiring and
+    releasing a lock or opening and closing a file is a powerful idea,
+    as can be seen by looking at the examples in that PEP.
+    Inspired by a counter-proposal to PEP 340 by Phillip Eby I tried
+    to create a decorator that would turn a suitable generator into an
+    object with the necessary __entry__ and __exit__ methods.  Here I
+    ran into a snag: while it wasn't too hard for the locking example,
+    it was impossible to do this for the opening example.  The idea
+    was to define the template like this:
+        @with_template
+        def opening(filename):
+            f = open(filename)
+            yield f
+            f.close()
+    and used it like this:
+        with f = opening(filename):
+            ...read data from f...
+    The problem is that in PEP 310, the result of calling EXPR is
+    assigned directly to VAR, and then VAR's __exit__ method is called
+    upon exit from BLOCK1.  But here, VAR clearly needs to receive the
+    opened file, and that would mean that __exit__ would have to be a
+    method on the file.
+    While this can be solved using a proxy class, this is awkward and
+    made me realize that a slightly different translation would make
+    writing the desired decorator a piece of cake: let VAR receive the
+    result from calling the __enter__ method, and save the value of
+    EXPR to call its __exit__ method later.  Then the decorator can
+    return an instance of a wrapper class whose __enter__ method calls
+    the generator's next() method and returns whatever next() returns;
+    the wrapper instance's __exit__ method calls next() again but
+    expects it to raise StopIteration.  (Details below in the section
+    Optional Generator Decorator.)
+    So now the final hurdle was that the PEP 310 syntax:
+        with VAR = EXPR:
+            BLOCK1
+    would be deceptive, since VAR does *not* receive the value of
+    EXPR.  Given PEP 340, it was an easy step to:
+        with EXPR as VAR:
+            BLOCK1
+    or, using an alternate keyword that has been proposed a number of
+    times:
+        do EXPR as VAR:
+            BLOCK1
 Use Cases
@@ -25,7 +121,7 @@
-    A new statement is proposed with the syntax
+    A new statement is proposed with the syntax:
         do EXPR as VAR:
@@ -53,7 +149,7 @@
                 exc = sys.exc_info()
-		raise
+                raise
@@ -66,7 +162,7 @@
     The calling convention for abc.__exit__() is: as follows.  If the
     finally-suite was reached through normal completion of BLOCK or
-    through a "non-local goto" (a break, continue or return statement
+    through a non-local goto (a break, continue or return statement
     in BLOCK), abc.__exit__() is called without arguments (or perhaps
     with three None arguments?).  If the finally-suite was reached
     through an exception raised in BLOCK, abc.__exit__() is called
@@ -122,18 +218,18 @@
     It would be possible to endow certain objects, like files,
     sockets, and locks, with __enter__ and __exit__ methods so that
-    instead of writing
+    instead of writing:
         do locking(myLock):
-    one could write simply
+    one could write simply:
         do myLock:
     I think we should be careful with this; it could lead to mistakes
-    like
+    like:
         f = open(filename)
         do f:
@@ -264,6 +360,10 @@
        as an exercise for the reader.  (Mail it to me if you'd like to
        see it here.)
+    [1] http://blogs.msdn.com/oldnewthing/archive/2005/01/06/347666.aspx
     This document has been placed in the public domain.

More information about the Python-checkins mailing list