diff options
author | Géry Ogam <gery.ogam@gmail.com> | 2019-12-30 05:24:51 (GMT) |
---|---|---|
committer | Nick Coghlan <ncoghlan@gmail.com> | 2019-12-30 05:24:51 (GMT) |
commit | 226e6e7d4326cf91ef37e13528eb1f62de1bb832 (patch) | |
tree | bb6922c83957c18b7080579a0165e1c261184847 /Doc/reference | |
parent | 32a12aed6da41f49a5ca05e6de34f5f93ea1dc33 (diff) | |
download | cpython-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.rst | 67 |
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. |