Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add a generators&coroutines section
  • Loading branch information
sterliakov committed Sep 1, 2024
commit c146cbd5d0fa23297a2dcbd7fc707d318d0f0b37
84 changes: 9 additions & 75 deletions Doc/library/collections.abc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -253,40 +253,9 @@ Collections Abstract Base Classes -- Detailed Descriptions
:meth:`~generator.send`,
:meth:`~generator.throw` and :meth:`~generator.close` methods.

A generator can be annotated by the generic type
``Generator[YieldType, SendType, ReturnType]``. For example::

def echo_round() -> Generator[int, float, str]:
sent = yield 0
while sent >= 0:
sent = yield round(sent)
return 'Done'

Note that unlike many other generics in the typing module, the ``SendType``
of :class:`Generator` behaves contravariantly, not covariantly or
invariantly.

The ``SendType`` and ``ReturnType`` parameters default to :const:`!None`::

def infinite_stream(start: int) -> Generator[int]:
while True:
yield start
start += 1

It is also possible to set these types explicitly::

def infinite_stream(start: int) -> Generator[int, None, None]:
while True:
yield start
start += 1

Alternatively, annotate your generator as having a return type of
either ``Iterable[YieldType]`` or ``Iterator[YieldType]``::

def infinite_stream(start: int) -> Iterator[int]:
while True:
yield start
start += 1
Refer to
:ref:`annotating generators and coroutines <annotating-generators-and-coroutines>`
Comment thread
AlexWaygood marked this conversation as resolved.
Outdated
section for details of using this class in type annotations.
Comment thread
AlexWaygood marked this conversation as resolved.
Outdated

.. versionadded:: 3.5

Expand Down Expand Up @@ -365,13 +334,9 @@ Collections Abstract Base Classes -- Detailed Descriptions
Use :func:`inspect.isawaitable` to detect them.

The variance and order of type variables
correspond to those of :class:`Generator`, for example::

from collections.abc import Coroutine
c: Coroutine[list[str], str, int] # Some coroutine defined elsewhere
x = c.send('hi') # Inferred type of 'x' is list[str]
async def bar() -> None:
y = await c # Inferred type of 'y' is int
correspond to those of :class:`Generator`. Refer to
:ref:`annotating generators and coroutines <annotating-generators-and-coroutines>`
section for details of using this class in type annotations.

.. versionadded:: 3.5

Expand All @@ -394,40 +359,9 @@ Collections Abstract Base Classes -- Detailed Descriptions
ABC for :term:`asynchronous generator` classes that implement the protocol
defined in :pep:`525` and :pep:`492`.

An async generator can be annotated by the generic type
``AsyncGenerator[YieldType, SendType]``. For example::

async def echo_round() -> AsyncGenerator[int, float]:
sent = yield 0
while sent >= 0.0:
rounded = await round(sent)
sent = yield rounded

Unlike normal generators, async generators cannot return a value, so there
is no ``ReturnType`` type parameter. As with :class:`Generator`, the
``SendType`` behaves contravariantly.

The ``SendType`` defaults to :const:`!None`::

async def infinite_stream(start: int) -> AsyncGenerator[int]:
while True:
yield start
start = await increment(start)

It is also possible to set this type explicitly::

async def infinite_stream(start: int) -> AsyncGenerator[int, None]:
while True:
yield start
start = await increment(start)

Alternatively, annotate your generator as having a return type of
either ``AsyncIterable[YieldType]`` or ``AsyncIterator[YieldType]``::

async def infinite_stream(start: int) -> AsyncIterator[int]:
while True:
yield start
start = await increment(start)
Refer to
:ref:`annotating generators and coroutines <annotating-generators-and-coroutines>`
section for details of using this class in type annotations.
Comment thread
AlexWaygood marked this conversation as resolved.
Outdated

.. versionadded:: 3.6

Expand Down
80 changes: 80 additions & 0 deletions Doc/library/typing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,86 @@ For example::
``type[Any]`` is equivalent to :class:`type`, which is the root of Python's
:ref:`metaclass hierarchy <metaclasses>`.


.. _annotating-generators-and-coroutines:

Annotating generators and coroutines
====================================

A generator can be annotated by the generic type
Comment thread
AlexWaygood marked this conversation as resolved.
Outdated
:class:`Generator[YieldType, SendType, ReturnType] <collections.abc.Generator>`.
For example::

def echo_round() -> Generator[int, float, str]:
sent = yield 0
while sent >= 0:
sent = yield round(sent)
return 'Done'

Note that unlike many other generics in the typing module, the ``SendType``
Comment thread
sterliakov marked this conversation as resolved.
Outdated
of :class:`~collections.abc.Generator` behaves contravariantly, not covariantly or
invariantly.

The ``SendType`` and ``ReturnType`` parameters default to :const:`!None`::

def infinite_stream(start: int) -> Generator[int]:
while True:
yield start
start += 1

It is also possible to set these types explicitly::

def infinite_stream(start: int) -> Generator[int, None, None]:
while True:
yield start
start += 1

Alternatively, annotate your generator as having a return type of
either :class:`Iterable[YieldType] <collections.abc.Iterable>`
Comment thread
AlexWaygood marked this conversation as resolved.
Outdated
or :class:`Iterator[YieldType] <collections.abc.Iterator>`::

def infinite_stream(start: int) -> Iterator[int]:
while True:
yield start
start += 1

Async generators are handled in a similar fashion, but don't
expect a `ReturnType` type argument
(:class:`AsyncGenerator[YieldType, SendType] <collections.abc.AsyncGenerator>`).
The `SendType` argument defaults to :const:`!None`, so the following definitions
are equivalent::

async def infinite_stream(start: int) -> AsyncGenerator[int]:
while True:
yield start
start = await increment(start)

async def infinite_stream(start: int) -> AsyncGenerator[int, None]:
while True:
yield start
start = await increment(start)

As in synchronous case,
Comment thread
AlexWaygood marked this conversation as resolved.
Outdated
:class:`AsyncIterable[YieldType] <collections.abc.AsyncIterable>`
and :class:`AsyncIterator[YieldType] <collections.abc.AsyncIterator>` are
available as well::

async def infinite_stream(start: int) -> AsyncIterator[int]:
while True:
yield start
start = await increment(start)

Coroutines can be annotated using
:class:`Coroutine[YieldType, SendType, ReturnType] <collections.abc.Coroutine>`.
Generic arguments correspond to those of :class:`~collections.abc.Generator`,
for example::

from collections.abc import Coroutine
c: Coroutine[list[str], str, int] # Some coroutine defined elsewhere
x = c.send('hi') # Inferred type of 'x' is list[str]
async def bar() -> None:
y = await c # Inferred type of 'y' is int

.. _user-defined-generics:

User-defined generic types
Expand Down