[3.11] gh-103921: Improve typing documentation (GH-104642) (#105007)

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
This commit is contained in:
Jelle Zijlstra 2023-05-27 16:30:41 -07:00 committed by GitHub
parent dcfa8165ad
commit d34e58a1d5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 190 additions and 158 deletions

View file

@ -136,6 +136,13 @@ Type aliases are useful for simplifying complex type signatures. For example::
Note that ``None`` as a type hint is a special case and is replaced by
``type(None)``.
Type aliases may be marked with :data:`TypeAlias` to make it explicit that
the statement is a type alias declaration, not a normal variable assignment::
from typing import TypeAlias
Vector: TypeAlias = list[float]
.. _distinct:
NewType
@ -367,7 +374,7 @@ You can use multiple inheritance with :class:`Generic`::
class LinkedList(Sized, Generic[T]):
...
When inheriting from generic classes, some type variables could be fixed::
When inheriting from generic classes, some type parameters could be fixed::
from collections.abc import Mapping
from typing import TypeVar
@ -387,7 +394,7 @@ not generic but implicitly inherits from ``Iterable[Any]``::
class MyIterable(Iterable): # Same as Iterable[Any]
User defined generic type aliases are also supported. Examples::
User-defined generic type aliases are also supported. Examples::
from collections.abc import Iterable
from typing import TypeVar
@ -423,7 +430,6 @@ to this is that a list of types can be used to substitute a :class:`ParamSpec`::
>>> Z[int, [dict, float]]
__main__.Z[int, (<class 'dict'>, <class 'float'>)]
Furthermore, a generic with only one parameter specification variable will accept
parameter lists in the forms ``X[[Type1, Type2, ...]]`` and also
``X[Type1, Type2, ...]`` for aesthetic reasons. Internally, the latter is converted
@ -1249,7 +1255,8 @@ These can be used as types in annotations using ``[]``, each having a unique syn
Building generic types
""""""""""""""""""""""
These are not used in annotations. They are building blocks for creating generic types.
The following objects are not used directly in annotations. Instead, they are building blocks
for creating generic types.
.. class:: Generic
@ -1275,7 +1282,7 @@ These are not used in annotations. They are building blocks for creating generic
except KeyError:
return default
.. class:: TypeVar
.. class:: TypeVar(name, *constraints, bound=None, covariant=False, contravariant=False)
Type variable.
@ -1287,7 +1294,8 @@ These are not used in annotations. They are building blocks for creating generic
Type variables exist primarily for the benefit of static type
checkers. They serve as the parameters for generic types as well
as for generic function definitions. See :class:`Generic` for more
as for generic function and type alias definitions.
See :class:`Generic` for more
information on generic types. Generic functions work as follows::
def repeat(x: T, n: int) -> Sequence[T]:
@ -1308,6 +1316,11 @@ These are not used in annotations. They are building blocks for creating generic
Note that type variables can be *bound*, *constrained*, or neither, but
cannot be both bound *and* constrained.
Created type variables may be explicitly marked covariant or contravariant by passing
``covariant=True`` or ``contravariant=True``.
By default, type variables are invariant.
See :pep:`484` and :pep:`695` for more details.
Bound type variables and constrained type variables have different
semantics in several important ways. Using a *bound* type variable means
that the ``TypeVar`` will be solved using the most specific type possible::
@ -1342,29 +1355,46 @@ These are not used in annotations. They are building blocks for creating generic
c = concatenate('one', b'two') # error: type variable 'A' can be either str or bytes in a function call, but not both
At runtime, ``isinstance(x, T)`` will raise :exc:`TypeError`. In general,
:func:`isinstance` and :func:`issubclass` should not be used with types.
At runtime, ``isinstance(x, T)`` will raise :exc:`TypeError`.
Type variables may be marked covariant or contravariant by passing
``covariant=True`` or ``contravariant=True``. See :pep:`484` for more
details. By default, type variables are invariant.
.. attribute:: __name__
.. class:: TypeVarTuple
The name of the type variable.
.. attribute:: __covariant__
Whether the type var has been marked as covariant.
.. attribute:: __contravariant__
Whether the type var has been marked as contravariant.
.. attribute:: __bound__
The bound of the type variable, if any.
.. attribute:: __constraints__
A tuple containing the constraints of the type variable, if any.
.. class:: TypeVarTuple(name)
Type variable tuple. A specialized form of :class:`type variable <TypeVar>`
that enables *variadic* generics.
Usage::
T = TypeVar("T")
Ts = TypeVarTuple("Ts")
def move_first_element_to_last(tup: tuple[T, *Ts]) -> tuple[*Ts, T]:
return (*tup[1:], tup[0])
A normal type variable enables parameterization with a single type. A type
variable tuple, in contrast, allows parameterization with an
*arbitrary* number of types by acting like an *arbitrary* number of type
variables wrapped in a tuple. For example::
T = TypeVar('T')
Ts = TypeVarTuple('Ts')
def move_first_element_to_last(tup: tuple[T, *Ts]) -> tuple[*Ts, T]:
return (*tup[1:], tup[0])
# T is bound to int, Ts is bound to ()
# Return value is (1,), which has type tuple[int]
move_first_element_to_last(tup=(1,))
@ -1400,7 +1430,7 @@ These are not used in annotations. They are building blocks for creating generic
Type variable tuples can be used in the same contexts as normal type
variables. For example, in class definitions, arguments, and return types::
Shape = TypeVarTuple('Shape')
Shape = TypeVarTuple("Shape")
class Array(Generic[*Shape]):
def __getitem__(self, key: tuple[*Shape]) -> float: ...
def __abs__(self) -> "Array[*Shape]": ...
@ -1445,6 +1475,10 @@ These are not used in annotations. They are building blocks for creating generic
See :pep:`646` for more details on type variable tuples.
.. attribute:: __name__
The name of the type variable tuple.
.. versionadded:: 3.11
.. class:: ParamSpec(name, *, bound=None, covariant=False, contravariant=False)
@ -1510,6 +1544,10 @@ These are not used in annotations. They are building blocks for creating generic
``P.args`` and ``P.kwargs`` are instances respectively of
:class:`ParamSpecArgs` and :class:`ParamSpecKwargs`.
.. attribute:: __name__
The name of the parameter specification.
Parameter specification variables created with ``covariant=True`` or
``contravariant=True`` can be used to declare covariant or contravariant
generic types. The ``bound`` argument is also accepted, similar to
@ -1672,6 +1710,8 @@ These are not used in annotations. They are building blocks for declaring types.
Protocol classes can be generic, for example::
T = TypeVar("T")
class GenProto(Protocol[T]):
def meth(self) -> T:
...

View file

@ -1177,17 +1177,9 @@ class ParamSpec(_Final, _Immutable, _BoundVarianceMixin, _PickleUsingNameMixin,
'''Add two numbers together.'''
return x + y
Parameter specification variables defined with covariant=True or
contravariant=True can be used to declare covariant or contravariant
generic types. These keyword arguments are valid, but their actual semantics
are yet to be decided. See PEP 612 for details.
Parameter specification variables can be introspected. e.g.:
P.__name__ == 'P'
P.__bound__ == None
P.__covariant__ == False
P.__contravariant__ == False
Note that only parameter specification variables defined in global scope can
be pickled.