[Python-checkins] python/nondist/peps pep-0343.txt, NONE, 1.1 pep-0000.txt, 1.305, 1.306

gvanrossum@users.sourceforge.net gvanrossum at users.sourceforge.net
Sat May 14 02:08:22 CEST 2005


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

Modified Files:
	pep-0000.txt 
Added Files:
	pep-0343.txt 
Log Message:
Add PEP 343: Anonymous Block Redux

--- NEW FILE: pep-0343.txt ---
PEP: 343
Title: Anonymous Block Redux
Version: $Revision: 1.1 $
Last-Modified: $Date: 2005/05/14 00:08:20 $
Author: Guido van Rossum
Status: Draft
Type: Standards Track
Content-Type: text/plain
Created: 13-May-2005
Post-History:

Introduction

    After a lot of discussion about PEP 340 and alternatives, I've
    decided to withdraw PEP 340 and propose a slight variant on PEP
    310.

Motivation and Summary

    TBD.

Use Cases

    See the Examples section near the end.

Specification

    A new statement is proposed with the syntax

        do EXPR as VAR:
            BLOCK

    Here, 'do' and 'as' are new keywords; EXPR is an arbitrary
    expression (but not an expression-list) and VAR is an arbitrary
    assignment target (which may be a comma-separated list).

    The "as VAR" part is optional.

    The choice of the 'do' keyword is provisional; an alternative
    under consideration is 'with'.

    A yield-statement is illegal inside BLOCK.  This is because the
    do-statement is translated into a try/finally statement, and yield
    is illegal in a try/finally statement.

    The translation of the above statement is:

        abc = EXPR
        try:
            VAR = abc.__enter__()
            BLOCK
        finally:
            abc.__exit__(*sys.exc_info())  # XXX See below

    If the "as VAR" part of the syntax is omitted, the "VAR =" part of
    the translation is omitted (but abc.__enter__() is still called).

    The call to abc.__exit__() is only approximated as written.  The
    actual calling convention is: If the finally-suite was reached
    through normal completion of BLOCK or 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 with three arguments
    representing the exception type, value, and traceback.

Optional Generator Decorator

    It is possible to write a decorator that makes it possible to use
    a generator that yields exactly once to control a do-statement.
    Here's a sketch of such a decorator:

	class Wrapper(object):
	   def __init__(self, gen):
	       self.gen = gen
	       self.state = "initial"
	   def __enter__(self):
	       assert self.state == "initial"
	       self.state = "entered"
	       try:
		   return self.gen.next()
	       except StopIteration:
		   self.state = "error"
		   raise RuntimeError("template generator didn't yield")
	   def __exit__(self, *args):
	       assert self.state == "entered"
	       self.state = "exited"
	       try:
		   self.gen.next()
	       except StopIteration:
		   return
	       else:
		   self.state = "error"
		   raise RuntimeError("template generator didn't stop")

	def do_template(func):
	   def helper(*args, **kwds):
	       return Wrapper(func(*args, **kwds))
	   return helper

    This decorator could be used as follows:

	@do_template
	def opening(filename):
	   f = open(filename) # IOError here is untouched by Wrapper
	   yield f
	   f.close() # Ditto for errors here (however unlikely)

    A robust implementation of such a decorator should be made part of
    the standard library.

Examples

    Several of these examples contain "yield None".  If PEP 342 is
    accepted, these can be changed to just "yield".

    1. A template for ensuring that a lock, acquired at the start of a
       block, is released when the block is left:

        @do_template
        def locking(lock):
            lock.acquire()
            yield None
            lock.release()

       Used as follows:

        do locking(myLock):
            # Code here executes with myLock held.  The lock is
            # guaranteed to be released when the block is left (even
            # if via return or by an uncaught exception).

    2. A template for opening a file that ensures the file is closed
       when the block is left:

        @do_template
        def opening(filename, mode="r"):
            f = open(filename, mode)
            yield f
            f.close()

       Used as follows:

        do opening("/etc/passwd") as f:
            for line in f:
                print line.rstrip()

    3. A template for committing or rolling back a database
       transaction; this is written as a class rather than as a
       decorator since it requires access to the exception information:

        class transactional:
            def __init__(self, db):
	        self.db = db
            def __enter__(self):
                pass
	    def __exit__(self, *args):
	        if args and args[0] is not None:
		    self.db.rollback()
		else:
		    self.db.commit()

    4. Example 1 rewritten without a generator:

        class locking:
           def __init__(self, lock):
               self.lock = lock
           def __enter__(self):
	       self.lock.acquire()
           def __exit__(self, *args):
	       self.lock.release()

       (This example is easily modified to implement the other
       examples; it shows how much simpler generators are for the same
       purpose.)

    5. Redirect stdout temporarily:

        @do_template
        def redirecting_stdout(new_stdout):
            save_stdout = sys.stdout
            try:
                sys.stdout = new_stdout
                yield None
            finally:
                sys.stdout = save_stdout

       Used as follows:

        do opening(filename, "w") as f:
            do redirecting_stdout(f):
                print "Hello world"

    6. A variant on opening() that also returns an error condition:

        @do_template
        def opening_w_error(filename, mode="r"):
            try:
                f = open(filename, mode)
            except IOError, err:
                yield None, err
            else:
	        yield f, None
                f.close()

       Used as follows:

        do opening_w_error("/etc/passwd", "a") as f, err:
            if err:
                print "IOError:", err
            else:
                f.write("guido::0:0::/:/bin/sh\n")

    7. Another useful example would be an operation that blocks
       signals.  The use could be like this:

        import signal

        do signal.blocking():
            # code executed without worrying about signals

       An optional argument might be a list of signals to be blocked;
       by default all signals are blocked.  The implementation is left
       as an exercise to the reader.

Copyright

    This document has been placed in the public domain.

Index: pep-0000.txt
===================================================================
RCS file: /cvsroot/python/python/nondist/peps/pep-0000.txt,v
retrieving revision 1.305
retrieving revision 1.306
diff -u -d -r1.305 -r1.306
--- pep-0000.txt	11 May 2005 21:58:13 -0000	1.305
+++ pep-0000.txt	14 May 2005 00:08:19 -0000	1.306
@@ -120,6 +120,7 @@
  S   340  Anonymous Block Statements                   GvR
  S   341  Unifying try-except and try-finally          Birkenfeld
  S   342  Enhanced Iterators                           GvR
+ S   343  Anonymous Block Redux                        GvR
  S   754  IEEE 754 Floating Point Special Values       Warnes
 
  Finished PEPs (done, implemented in CVS)
@@ -380,6 +381,7 @@
  S   340  Anonymous Block Statements                   GvR
  S   341  Unifying try-except and try-finally          Birkenfeld
  S   342  Enhanced Iterators                           GvR
+ S   343  Anonymous Block Redux                        GvR
  SR  666  Reject Foolish Indentation                   Creighton
  S   754  IEEE 754 Floating Point Special Values       Warnes
  I  3000  Python 3.0 Plans                             Kuchling, Cannon



More information about the Python-checkins mailing list