Add some more to the rationale section in PEP 377
This commit is contained in:
parent
2d3b72243a
commit
01ddf563f6
116
pep-0377.txt
116
pep-0377.txt
|
@ -129,40 +129,95 @@ then handles and suppresses::
|
|||
# instead of as classes!)
|
||||
class CM(object):
|
||||
def __init__(self):
|
||||
self.cmA = None
|
||||
self.cmB = None
|
||||
self.cmA = None
|
||||
self.cmB = None
|
||||
|
||||
def __enter__(self):
|
||||
if self.cmA is not None:
|
||||
raise RuntimeError("Can't re-use this CM")
|
||||
self.cmA = cmA()
|
||||
self.cmA.__enter__()
|
||||
try:
|
||||
self.cmB = cmB()
|
||||
self.cmB.__enter__()
|
||||
except:
|
||||
self.cmA.__exit__(*sys.exc_info())
|
||||
# Can't suppress in __enter__(), so must raise
|
||||
raise
|
||||
if self.cmA is not None:
|
||||
raise RuntimeError("Can't re-use this CM")
|
||||
self.cmA = cmA()
|
||||
self.cmA.__enter__()
|
||||
try:
|
||||
self.cmB = cmB()
|
||||
self.cmB.__enter__()
|
||||
except:
|
||||
self.cmA.__exit__(*sys.exc_info())
|
||||
# Can't suppress in __enter__(), so must raise
|
||||
raise
|
||||
|
||||
def __exit__(self, *args):
|
||||
suppress = False
|
||||
try:
|
||||
if self.cmB is not None:
|
||||
suppress = self.cmB.__exit__(*args)
|
||||
except:
|
||||
suppress = self.cmA.__exit__(*sys.exc_info()):
|
||||
if not suppress:
|
||||
# Exception has changed, so reraise explicitly
|
||||
raise
|
||||
suppress = False
|
||||
try:
|
||||
if self.cmB is not None:
|
||||
suppress = self.cmB.__exit__(*args)
|
||||
except:
|
||||
suppress = self.cmA.__exit__(*sys.exc_info()):
|
||||
if not suppress:
|
||||
# Exception has changed, so reraise explicitly
|
||||
raise
|
||||
else:
|
||||
if suppress:
|
||||
# cmB already suppressed the exception,
|
||||
# so don't pass it to cmA
|
||||
suppress = self.cmA.__exit__(None, None, None):
|
||||
else:
|
||||
if suppress:
|
||||
# cmB already suppressed the exception,
|
||||
# so don't pass it to cmA
|
||||
suppress = self.cmA.__exit__(None, None, None):
|
||||
else:
|
||||
suppress = self.cmA.__exit__(*args):
|
||||
return suppress
|
||||
suppress = self.cmA.__exit__(*args):
|
||||
return suppress
|
||||
|
||||
With the proposed semantic change in place, the contextlib based examples
|
||||
above would then "just work", but the class based version would need
|
||||
adjustment to take advantage of the new semantics::
|
||||
|
||||
class CM(object):
|
||||
def __init__(self):
|
||||
self.cmA = None
|
||||
self.cmB = None
|
||||
|
||||
def __enter__(self):
|
||||
if self.cmA is not None:
|
||||
raise RuntimeError("Can't re-use this CM")
|
||||
self.cmA = cmA()
|
||||
self.cmA.__enter__()
|
||||
try:
|
||||
self.cmB = cmB()
|
||||
self.cmB.__enter__()
|
||||
except:
|
||||
if self.cmA.__exit__(*sys.exc_info()):
|
||||
# Suppress the exception, but don't run
|
||||
# the body of the with statement either
|
||||
raise SkipStatement
|
||||
raise
|
||||
|
||||
def __exit__(self, *args):
|
||||
suppress = False
|
||||
try:
|
||||
if self.cmB is not None:
|
||||
suppress = self.cmB.__exit__(*args)
|
||||
except:
|
||||
suppress = self.cmA.__exit__(*sys.exc_info()):
|
||||
if not suppress:
|
||||
# Exception has changed, so reraise explicitly
|
||||
raise
|
||||
else:
|
||||
if suppress:
|
||||
# cmB already suppressed the exception,
|
||||
# so don't pass it to cmA
|
||||
suppress = self.cmA.__exit__(None, None, None):
|
||||
else:
|
||||
suppress = self.cmA.__exit__(*args):
|
||||
return suppress
|
||||
|
||||
There is currently a tentative suggestion [3] to add import-style syntax to
|
||||
the ``with`` statement to allow multiple context managers to be included in
|
||||
a single ``with`` statement without needing to use ``contextlib.nested``. In
|
||||
that case the compiler has the option of simply emitting multiple ``with``
|
||||
statements at the AST level, thus allowing the semantics of actual nested
|
||||
``with`` statements to be reproduced accurately. However, such a change
|
||||
would highlight rather than alleviate the problem the current PEP aims to
|
||||
address: it would not be possible to use ``contextlib.contextmanager``to
|
||||
reliably factor out such ``with`` statements, as they would exhibit exactly
|
||||
the same semantic differences as are seen with the ``combined()`` context
|
||||
manager in the above example.
|
||||
|
||||
|
||||
Reference Implementation
|
||||
|
@ -186,6 +241,9 @@ References
|
|||
.. [2] PEP 343: The "with" Statement
|
||||
(http://www.python.org/dev/peps/pep-0343/)
|
||||
|
||||
.. [3] Import-style syntax to reduce indentation of nested with statements
|
||||
(http://mail.python.org/pipermail/python-ideas/2009-March/003188.html)
|
||||
|
||||
Copyright
|
||||
=========
|
||||
|
||||
|
|
Loading…
Reference in New Issue