Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bpo-39037: Look up __enter__ before __exit__ in the with statement documentation #17608

Merged
merged 8 commits into from
Dec 30, 2019
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:
geryogam marked this conversation as resolved.
Show resolved Hide resolved
if not hit_except:
await aexit(manager, None, None, None)

See also :meth:`__aenter__` and :meth:`__aexit__` for details.

Expand Down