Skip to content

Commit

Permalink
bpo-39037: Fix lookup order of magic methods in with statement docume…
Browse files Browse the repository at this point in the history
…ntation (pythonGH-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.
  • Loading branch information
geryogam authored and ncoghlan committed Dec 30, 2019
1 parent 32a12ae commit 226e6e7
Showing 1 changed file with 49 additions and 18 deletions.
67 changes: 49 additions & 18 deletions Doc/reference/compound_stmts.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.

Expand All @@ -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.

Expand Down

0 comments on commit 226e6e7

Please sign in to comment.