[3.13] gh-123523: Rework typing documentation for generators and coroutines, and link to it from `collections.abc` docs (GH-123544) by miss-islington · Pull Request #123790 · python/cpython
Functions -- or other :term:`callable` objects -- can be annotated using :class:`collections.abc.Callable` or :data:`typing.Callable`. :class:`collections.abc.Callable` or deprecated :data:`typing.Callable`. ``Callable[[int], str]`` signifies a function that takes a single parameter of type :class:`int` and returns a :class:`str`.
A variable annotated with ``C`` may accept a value of type ``C``. In contrast, a variable annotated with ``type[C]`` (or contrast, a variable annotated with ``type[C]`` (or deprecated :class:`typing.Type[C] <Type>`) may accept values that are classes themselves -- specifically, it will accept the *class object* of ``C``. For example::
.. _annotating-generators-and-coroutines:
Annotating generators and coroutines ====================================
A generator can be annotated using the generic type :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 generic classes in the standard library, the ``SendType`` 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
Simple generators that only ever yield values can also be annotated as having a return type of either :class:`Iterable[YieldType] <collections.abc.Iterable>` 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 the synchronous case, :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
Note that to annotate arguments, it is preferred to use an abstract collection type such as :class:`Mapping` to use an abstract collection type such as :class:`~collections.abc.Mapping` rather than to use :class:`dict` or :class:`!typing.Dict`.
This type can be used as follows::
def count_words(text: str) -> Dict[str, int]: ...
.. deprecated:: 3.9 :class:`builtins.dict <dict>` now supports subscripting (``[]``). See :pep:`585` and :ref:`types-genericalias`.
Note that to annotate arguments, it is preferred to use an abstract collection type such as :class:`Sequence` or :class:`Iterable` rather than to use :class:`list` or :class:`!typing.List`.
This type may be used as follows::
def vec2[T: (int, float)](x: T, y: T) -> List[T]: return [x, y]
def keep_positives[T: (int, float)](vector: Sequence[T]) -> List[T]: return [item for item in vector if item > 0] to use an abstract collection type such as :class:`~collections.abc.Sequence` or :class:`~collections.abc.Iterable` rather than to use :class:`list` or :class:`!typing.List`.
.. deprecated:: 3.9 :class:`builtins.list <list>` now supports subscripting (``[]``).
Note that to annotate arguments, it is preferred to use an abstract collection type such as :class:`AbstractSet` rather than to use :class:`set` or :class:`!typing.Set`. to use an abstract collection type such as :class:`collections.abc.Set` rather than to use :class:`set` or :class:`typing.Set`.
.. deprecated:: 3.9 :class:`builtins.set <set>` now supports subscripting (``[]``).
Deprecated alias to :class:`collections.abc.Mapping`.
This type can be used as follows::
def get_position_in_index(word_list: Mapping[str, int], word: str) -> int: return word_list[word]
.. deprecated:: 3.9 :class:`collections.abc.Mapping` now supports subscripting (``[]``). See :pep:`585` and :ref:`types-genericalias`.
Deprecated alias to :class:`collections.abc.Coroutine`.
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 See :ref:`annotating-generators-and-coroutines` for details on using :class:`collections.abc.Coroutine` and ``typing.Coroutine`` in type annotations.
.. versionadded:: 3.5.3
Deprecated alias to :class:`collections.abc.AsyncGenerator`.
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) See :ref:`annotating-generators-and-coroutines` for details on using :class:`collections.abc.AsyncGenerator` and ``typing.AsyncGenerator`` in type annotations.
.. versionadded:: 3.6.1
Deprecated alias to :class:`collections.abc.Generator`.
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 See :ref:`annotating-generators-and-coroutines` for details on using :class:`collections.abc.Generator` and ``typing.Generator`` in type annotations.
.. deprecated:: 3.9 :class:`collections.abc.Generator` now supports subscripting (``[]``).