Skip to content

Commit 15fcd7e

Browse files
committed
Add a bunch of documentation.
1 parent 5019628 commit 15fcd7e

3 files changed

Lines changed: 105 additions & 1 deletion

File tree

Doc/library/exceptions.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,8 +524,19 @@ The following exceptions are the exceptions that are usually raised.
524524
Must be raised by :meth:`~object.__anext__` method of an
525525
:term:`asynchronous iterator` object to stop the iteration.
526526

527+
.. attribute:: StopAsyncIteration.value
528+
529+
This is given as an argument when constructing the exception, and
530+
defaults to :const:`None`. This is used for the result of
531+
``async yield from`` expressions (see :ref:`async-yield-from`).
532+
533+
.. versionadded: next
534+
527535
.. versionadded:: 3.5
528536

537+
.. versionchanged:: next
538+
Added the ``value`` attribute.
539+
529540
.. exception:: SyntaxError(message, details)
530541

531542
Raised when the parser encounters a syntax error. This may occur in an

Doc/reference/expressions.rst

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,7 @@ Yield expressions
629629
yield_atom: "(" `yield_expression` ")"
630630
yield_from: "yield" "from" `expression`
631631
yield_expression: "yield" `yield_list` | `yield_from`
632+
async_yield_from: "async" "yield" "from" `expression`
632633

633634
The yield expression is used when defining a :term:`generator` function
634635
or an :term:`asynchronous generator` function and
@@ -708,6 +709,10 @@ the yield expression. It can be either set explicitly when raising
708709
.. versionchanged:: 3.3
709710
Added ``yield from <expr>`` to delegate control flow to a subiterator.
710711

712+
.. versionchanged:: next
713+
``yield from`` is now allowed to be used in an async generator.
714+
Previously, it would raise a :class:`SyntaxError`.
715+
711716
The parentheses may be omitted when the yield expression is the sole expression
712717
on the right hand side of an assignment statement.
713718

@@ -728,6 +733,10 @@ on the right hand side of an assignment statement.
728733
The proposal that expanded on :pep:`492` by adding generator capabilities to
729734
coroutine functions.
730735

736+
:pep:`828` - Supporting ``yield from`` in asynchronous generators
737+
The proposal that expanded on :pep:`380` by adding subgenerator delegation
738+
to asynchronous generators.
739+
731740
.. index:: pair: object; generator
732741
.. _generator-methods:
733742

@@ -913,7 +922,89 @@ registered *finalizer* to be called upon finalization. For a reference example
913922
of a *finalizer* method see the implementation of
914923
``asyncio.Loop.shutdown_asyncgens`` in :source:`Lib/asyncio/base_events.py`.
915924

916-
The expression ``yield from <expr>`` is a syntax error when used in an
925+
.. _async-yield-from:
926+
927+
Asynchronous ``yield from``
928+
^^^^^^^^^^^^^^^^^^^^^^^^^^^
929+
930+
Conceptually, ``async yield from`` is very similar to ``yield from``, but
931+
operates solely on asynchronous constructs rather than synchronous ones.
932+
In particular:
933+
934+
.. list-table::
935+
:widths: auto
936+
:header-rows: 1
937+
938+
* * ``yield from`` construct
939+
* ``async yield from`` construct
940+
* * :meth:`~object.__iter__`
941+
* :meth:`~object.__aiter__`
942+
* * :meth:`~generator.__next__`
943+
* :meth:`~agen.__anext__`
944+
* * :meth:`~generator.send`
945+
* :meth:`~agen.asend`
946+
* * :class:`StopIteration`
947+
* :class:`StopAsyncIteration`
948+
949+
To describe the above:
950+
951+
* The object being delegated to must be asynchronously iterable (that is, it
952+
must implement ``__aiter__`` instead of ``__iter__``).
953+
* When ``anext`` is called on the parent generator (the one that contains
954+
``async yield from``), ``__anext__`` will be invoked on the subgenerator.
955+
In contrast, a synchronous ``yield from`` would invoke ``__next__`` instead.
956+
(Note that calling ``asend`` with a ``None`` value is equivalent to calling
957+
``anext()``, and thus applies here.)
958+
* All calls to ``asend``, ``athrow``, and ``aclose`` are delegated to the
959+
subgenerator (the object returned by ``__aiter__`` in this case). This means
960+
that a call to ``parent_generator.asend(x)`` is semantically equivalent to
961+
``sub_generator.asend(x)``, where ``parent_generator`` is currently executing
962+
an ``async yield from`` on ``sub_generator``.
963+
* The result of the expression is retrieved through
964+
:attr:`StopAsyncIteration.value` instead of :attr:`StopIteration.value`.
965+
966+
An example of usage for ``async yield from``:
967+
968+
.. code-block:: pycon
969+
970+
>>> import asyncio
971+
>>> async def sleepy_count(number):
972+
... for num in range(number):
973+
... await asyncio.sleep(1)
974+
... result = yield num
975+
... print(f"Got result: {result}")
976+
...
977+
>>> async def counter():
978+
... final_number = async yield from sleepy_count(5)
979+
... yield final_number
980+
...
981+
>>> await anext(ag)
982+
0
983+
>>> await anext(ag)
984+
Got result: None
985+
1
986+
>>> await ag.asend(42)
987+
Got result: 42
988+
2
989+
>>> await ag.athrow(ValueError("Nobody expects the Spanish Inquisition"))
990+
Traceback (most recent call last):
991+
File "/home/python/cpython/Lib/concurrent/futures/_base.py", line 450, in result
992+
return self.__get_result()
993+
~~~~~~~~~~~~~~~~~^^
994+
File "/home/python/cpython/Lib/concurrent/futures/_base.py", line 395, in __get_result
995+
raise self._exception
996+
File "<python-input-4>", line 1, in <module>
997+
await ag.athrow(ValueError("Nobody expects the Spanish Inquisition"))
998+
File "<python-input-0>", line 8, in counter
999+
final_number = async yield from sleepy_count(4)
1000+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1001+
File "<python-input-0>", line 3, in sleepy_count
1002+
result = yield num
1003+
^^^^^^^^^
1004+
ValueError: Nobody expects the Spanish Inquisition
1005+
1006+
1007+
``async yield from`` is a :class:`SyntaxError` when used outside of an
9171008
asynchronous generator function.
9181009

9191010
.. index:: pair: object; asynchronous-generator

Doc/reference/simple_stmts.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,11 +534,13 @@ statement. For example, the yield statements ::
534534

535535
yield <expr>
536536
yield from <expr>
537+
async yield from <expr>
537538

538539
are equivalent to the yield expression statements ::
539540

540541
(yield <expr>)
541542
(yield from <expr>)
543+
(async yield from <expr>)
542544

543545
Yield expressions and statements are only used when defining a :term:`generator`
544546
function, and are only used in the body of the generator function. Using :keyword:`yield`

0 commit comments

Comments
 (0)