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!)
|
# instead of as classes!)
|
||||||
class CM(object):
|
class CM(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.cmA = None
|
self.cmA = None
|
||||||
self.cmB = None
|
self.cmB = None
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
if self.cmA is not None:
|
if self.cmA is not None:
|
||||||
raise RuntimeError("Can't re-use this CM")
|
raise RuntimeError("Can't re-use this CM")
|
||||||
self.cmA = cmA()
|
self.cmA = cmA()
|
||||||
self.cmA.__enter__()
|
self.cmA.__enter__()
|
||||||
try:
|
try:
|
||||||
self.cmB = cmB()
|
self.cmB = cmB()
|
||||||
self.cmB.__enter__()
|
self.cmB.__enter__()
|
||||||
except:
|
except:
|
||||||
self.cmA.__exit__(*sys.exc_info())
|
self.cmA.__exit__(*sys.exc_info())
|
||||||
# Can't suppress in __enter__(), so must raise
|
# Can't suppress in __enter__(), so must raise
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def __exit__(self, *args):
|
def __exit__(self, *args):
|
||||||
suppress = False
|
suppress = False
|
||||||
try:
|
try:
|
||||||
if self.cmB is not None:
|
if self.cmB is not None:
|
||||||
suppress = self.cmB.__exit__(*args)
|
suppress = self.cmB.__exit__(*args)
|
||||||
except:
|
except:
|
||||||
suppress = self.cmA.__exit__(*sys.exc_info()):
|
suppress = self.cmA.__exit__(*sys.exc_info()):
|
||||||
if not suppress:
|
if not suppress:
|
||||||
# Exception has changed, so reraise explicitly
|
# Exception has changed, so reraise explicitly
|
||||||
raise
|
raise
|
||||||
|
else:
|
||||||
|
if suppress:
|
||||||
|
# cmB already suppressed the exception,
|
||||||
|
# so don't pass it to cmA
|
||||||
|
suppress = self.cmA.__exit__(None, None, None):
|
||||||
else:
|
else:
|
||||||
if suppress:
|
suppress = self.cmA.__exit__(*args):
|
||||||
# cmB already suppressed the exception,
|
return suppress
|
||||||
# so don't pass it to cmA
|
|
||||||
suppress = self.cmA.__exit__(None, None, None):
|
With the proposed semantic change in place, the contextlib based examples
|
||||||
else:
|
above would then "just work", but the class based version would need
|
||||||
suppress = self.cmA.__exit__(*args):
|
adjustment to take advantage of the new semantics::
|
||||||
return suppress
|
|
||||||
|
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
|
Reference Implementation
|
||||||
|
@ -186,6 +241,9 @@ References
|
||||||
.. [2] PEP 343: The "with" Statement
|
.. [2] PEP 343: The "with" Statement
|
||||||
(http://www.python.org/dev/peps/pep-0343/)
|
(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
|
Copyright
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue