Update this PEP to reflect the new design: exceptions are swallowed only

when __exit__ returns a true value.
This commit is contained in:
Guido van Rossum 2006-03-09 17:39:53 +00:00
parent 03a9d2dab8
commit f6659b5348
1 changed files with 17 additions and 12 deletions

View File

@ -236,7 +236,9 @@ Specification: The 'with' Statement
except: except:
# The exceptional case is handled here # The exceptional case is handled here
exc = False exc = False
exit(*sys.exc_info()) if not exit(*sys.exc_info()):
raise
# The exception is swallowed if exit() returns true
finally: finally:
# The normal and non-local-goto cases are handled here # The normal and non-local-goto cases are handled here
if exc: if exc:
@ -277,17 +279,21 @@ Specification: The 'with' Statement
BLOCK, ctx.__exit__() is called with three arguments representing BLOCK, ctx.__exit__() is called with three arguments representing
the exception type, value, and traceback. the exception type, value, and traceback.
IMPORTANT: if ctx.__exit__() is passed exception information, it IMPORTANT: if ctx.__exit__() returns a "true" value, the exception
*must* re-raise the exception, unless it wants the exception to be is "swallowed". That is, if it returns "true", execution
ignored. That is, if ctx.__exit__() returns normally, execution
continues at the next statement after the with-statement, even if continues at the next statement after the with-statement, even if
an exception happened inside the with-statement. However, if the an exception happened inside the with-statement. However, if the
with-statement was left via a non-local goto (break, continue or with-statement was left via a non-local goto (break, continue or
return), this non-local return is resumed when ctx.__exit__() return), this non-local return is resumed when ctx.__exit__()
returns normally. The motivation for this detail is to make a returns regardless of the return value. The motivation for this
try/except block in a context manager created from a decorated detail is to make it possible for ctx.__exit__() to swallow
generator behave exactly as if the body of the generator were exceptions, without making it too easy (since the default return
expanded in-line at the place of the with-statement. value, None, is false and this causes the exception to be
re-raised). The main use case for swallowing exceptions is to
make it possible to write the @contextmanager decorator so thatn
that a try/except block in a decorated generator behaves exactly
as if the body of the generator were expanded in-line at the place
of the with-statement.
The motivation for passing the exception details to __exit__(), as The motivation for passing the exception details to __exit__(), as
opposed to the argument-less __exit__() from PEP 310, was given by opposed to the argument-less __exit__() from PEP 310, was given by
@ -351,10 +357,9 @@ Generator Decorator
else: else:
try: try:
self.gen.throw(type, value, traceback) self.gen.throw(type, value, traceback)
except (type, StopIteration): return True
return except StopIteration:
else: return True
raise RuntimeError("generator caught exception")
def contextmanager(func): def contextmanager(func):
def helper(*args, **kwds): def helper(*args, **kwds):