[Python-checkins] r70363 - peps/trunk/pep-0377.txt

nick.coghlan python-checkins at python.org
Sat Mar 14 08:28:36 CET 2009


Author: nick.coghlan
Date: Sat Mar 14 08:28:35 2009
New Revision: 70363

Log:
Add some more to the rationale section in PEP 377

Modified:
   peps/trunk/pep-0377.txt

Modified: peps/trunk/pep-0377.txt
==============================================================================
--- peps/trunk/pep-0377.txt	(original)
+++ peps/trunk/pep-0377.txt	Sat Mar 14 08:28:35 2009
@@ -129,40 +129,95 @@
   # 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
+      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
+      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
+
+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
+      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
+
+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 @@
 .. [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
 =========
 


More information about the Python-checkins mailing list