summaryrefslogtreecommitdiffstats
path: root/Doc/reference
diff options
context:
space:
mode:
authorGéry Ogam <gery.ogam@gmail.com>2019-12-30 05:24:51 (GMT)
committerNick Coghlan <ncoghlan@gmail.com>2019-12-30 05:24:51 (GMT)
commit226e6e7d4326cf91ef37e13528eb1f62de1bb832 (patch)
treebb6922c83957c18b7080579a0165e1c261184847 /Doc/reference
parent32a12aed6da41f49a5ca05e6de34f5f93ea1dc33 (diff)
downloadcpython-226e6e7d4326cf91ef37e13528eb1f62de1bb832.zip
cpython-226e6e7d4326cf91ef37e13528eb1f62de1bb832.tar.gz
cpython-226e6e7d4326cf91ef37e13528eb1f62de1bb832.tar.bz2
bpo-39037: Fix lookup order of magic methods in with statement documentation (GH-17608)
* __enter__ is now looked up before __exit__ to give a more intuitive error message * add pseudo-code equivalent for the with statement * fix pseudo-code for the async with statement to use a finally clause * use SUITE rather than BLOCK for consistency with the language grammar Patch by Géry Ogam.
Diffstat (limited to 'Doc/reference')
-rw-r--r--Doc/reference/compound_stmts.rst67
1 files changed, 49 insertions, 18 deletions
diff --git a/Doc/reference/compound_stmts.rst b/Doc/reference/compound_stmts.rst
index 988eec6..564d6cc 100644
--- a/Doc/reference/compound_stmts.rst
+++ b/Doc/reference/compound_stmts.rst
@@ -399,6 +399,8 @@ The execution of the :keyword:`with` statement with one "item" proceeds as follo
#. The context expression (the expression given in the :token:`with_item`) is
evaluated to obtain a context manager.
+#. The context manager's :meth:`__enter__` is loaded for later use.
+
#. The context manager's :meth:`__exit__` is loaded for later use.
#. The context manager's :meth:`__enter__` method is invoked.
@@ -430,17 +432,41 @@ The execution of the :keyword:`with` statement with one "item" proceeds as follo
value from :meth:`__exit__` is ignored, and execution proceeds at the normal
location for the kind of exit that was taken.
+The following code::
+
+ with EXPRESSION as TARGET:
+ SUITE
+
+is semantically equivalent to::
+
+ manager = (EXPRESSION)
+ enter = type(manager).__enter__
+ exit = type(manager).__exit__
+ value = enter(manager)
+ hit_except = False
+
+ try:
+ TARGET = value
+ SUITE
+ except:
+ hit_except = True
+ if not exit(manager, *sys.exc_info()):
+ raise
+ finally:
+ if not hit_except:
+ exit(manager, None, None, None)
+
With more than one item, the context managers are processed as if multiple
:keyword:`with` statements were nested::
with A() as a, B() as b:
- suite
+ SUITE
-is equivalent to ::
+is semantically equivalent to::
with A() as a:
with B() as b:
- suite
+ SUITE
.. versionchanged:: 3.1
Support for multiple context expressions.
@@ -772,24 +798,25 @@ iterators.
The following code::
async for TARGET in ITER:
- BLOCK
+ SUITE
else:
- BLOCK2
+ SUITE2
Is semantically equivalent to::
iter = (ITER)
iter = type(iter).__aiter__(iter)
running = True
+
while running:
try:
TARGET = await type(iter).__anext__(iter)
except StopAsyncIteration:
running = False
else:
- BLOCK
+ SUITE
else:
- BLOCK2
+ SUITE2
See also :meth:`__aiter__` and :meth:`__anext__` for details.
@@ -811,23 +838,27 @@ able to suspend execution in its *enter* and *exit* methods.
The following code::
- async with EXPR as VAR:
- BLOCK
+ async with EXPRESSION as TARGET:
+ SUITE
-Is semantically equivalent to::
+is semantically equivalent to::
- mgr = (EXPR)
- aexit = type(mgr).__aexit__
- aenter = type(mgr).__aenter__(mgr)
+ manager = (EXPRESSION)
+ aexit = type(manager).__aexit__
+ aenter = type(manager).__aenter__
+ value = await aenter(manager)
+ hit_except = False
- VAR = await aenter
try:
- BLOCK
+ TARGET = value
+ SUITE
except:
- if not await aexit(mgr, *sys.exc_info()):
+ hit_except = True
+ if not await aexit(manager, *sys.exc_info()):
raise
- else:
- await aexit(mgr, None, None, None)
+ finally:
+ if not hit_except:
+ await aexit(manager, None, None, None)
See also :meth:`__aenter__` and :meth:`__aexit__` for details.