[Python-checkins] python/nondist/peps pep-0343.txt,1.1,1.2
gvanrossum@users.sourceforge.net
gvanrossum at users.sourceforge.net
Sat May 14 04:02:42 CEST 2005
Update of /cvsroot/python/python/nondist/peps
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv25715
Modified Files:
pep-0343.txt
Log Message:
Don't be wishy-washy about the call to __exit__().
Fix the redirecting_stdout() example (remove the try/finally).
Index: pep-0343.txt
===================================================================
RCS file: /cvsroot/python/python/nondist/peps/pep-0343.txt,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- pep-0343.txt 14 May 2005 00:08:20 -0000 1.1
+++ pep-0343.txt 14 May 2005 02:02:40 -0000 1.2
@@ -46,23 +46,28 @@
The translation of the above statement is:
abc = EXPR
+ exc = () # Or (None, None, None) ?
try:
- VAR = abc.__enter__()
- BLOCK
+ try:
+ VAR = abc.__enter__()
+ BLOCK
+ except:
+ exc = sys.exc_info()
+ raise
finally:
- abc.__exit__(*sys.exc_info()) # XXX See below
+ abc.__exit__(exc)
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.
+ 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
+ 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
@@ -70,41 +75,41 @@
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")
+ 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
+ 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)
+ @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.
@@ -151,14 +156,14 @@
class transactional:
def __init__(self, db):
- self.db = 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()
+ 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:
@@ -166,9 +171,9 @@
def __init__(self, lock):
self.lock = lock
def __enter__(self):
- self.lock.acquire()
+ self.lock.acquire()
def __exit__(self, *args):
- self.lock.release()
+ self.lock.release()
(This example is easily modified to implement the other
examples; it shows how much simpler generators are for the same
@@ -179,11 +184,9 @@
@do_template
def redirecting_stdout(new_stdout):
save_stdout = sys.stdout
- try:
- sys.stdout = new_stdout
- yield None
- finally:
- sys.stdout = save_stdout
+ sys.stdout = new_stdout
+ yield None
+ sys.stdout = save_stdout
Used as follows:
@@ -200,7 +203,7 @@
except IOError, err:
yield None, err
else:
- yield f, None
+ yield f, None
f.close()
Used as follows:
More information about the Python-checkins
mailing list