[3.12] gh-103921: Document PEP 695 (GH-104642) (#104989)

(cherry picked from commit 060277d96b)

Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
This commit is contained in:
Miss Islington (bot) 2023-05-26 11:19:34 -07:00 committed by GitHub
parent bb1e57ee40
commit dcee0aa911
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 1240 additions and 308 deletions

View file

@ -443,45 +443,38 @@ static PyMethodDef typevar_methods[] = {
PyDoc_STRVAR(typevar_doc,
"Type variable.\n\
\n\
Usage::\n\
The preferred way to construct a type variable is via the dedicated syntax\n\
for generic functions, classes, and type aliases:\n\
\n\
T = TypeVar('T') # Can be anything\n\
A = TypeVar('A', str, bytes) # Must be str or bytes\n\
class Sequence[T]: # T is a TypeVar\n\
...\n\
\n\
This syntax can also be used to create bound and constrained type\n\
variables:\n\
\n\
class StrSequence[S: str]: # S is a TypeVar bound to str\n\
...\n\
\n\
class StrOrBytesSequence[A: (str, bytes)]: # A is a TypeVar constrained to str or bytes\n\
...\n\
\n\
However, if desired, reusable type variables can also be constructed\n\
manually, like so:\n\
\n\
T = TypeVar('T') # Can be anything\n\
S = TypeVar('S', bound=str) # Can be any subtype of str\n\
A = TypeVar('A', str, bytes) # Must be exactly str or bytes\n\
\n\
Type variables exist primarily for the benefit of static type\n\
checkers. They serve as the parameters for generic types as well\n\
as for generic function definitions. See class Generic for more\n\
information on generic types. Generic functions work as follows:\n\
as for generic function and type alias definitions.\n\
\n\
def repeat(x: T, n: int) -> List[T]:\n\
'''Return a list containing n references to x.'''\n\
return [x]*n\n\
\n\
def longest(x: A, y: A) -> A:\n\
'''Return the longest of two strings.'''\n\
return x if len(x) >= len(y) else y\n\
\n\
The latter example's signature is essentially the overloading\n\
of (str, str) -> str and (bytes, bytes) -> bytes. Also note\n\
that if the arguments are instances of some subclass of str,\n\
the return type is still plain str.\n\
\n\
At runtime, isinstance(x, T) and issubclass(C, T) will raise TypeError.\n\
\n\
Type variables defined with covariant=True or contravariant=True\n\
can be used to declare covariant or contravariant generic types.\n\
See PEP 484 for more details. By default generic types are invariant\n\
in all type variables.\n\
\n\
Type variables can be introspected. e.g.:\n\
\n\
T.__name__ == 'T'\n\
T.__constraints__ == ()\n\
T.__covariant__ == False\n\
T.__contravariant__ = False\n\
A.__constraints__ == (str, bytes)\n\
\n\
Note that only type variables defined in global scope can be pickled.\n\
The variance of type variables is inferred by type checkers when they are created\n\
through the type parameter syntax and when ``infer_variance=True`` is passed.\n\
Manually created type variables may be explicitly marked covariant or\n\
contravariant by passing ``covariant=True`` or ``contravariant=True``.\n\
By default, manually created type variables are invariant. See PEP 484\n\
and PEP 695 for more details.\n\
");
static PyType_Slot typevar_slots[] = {
@ -942,7 +935,14 @@ static PyMethodDef paramspec_methods[] = {
PyDoc_STRVAR(paramspec_doc,
"Parameter specification variable.\n\
\n\
Usage::\n\
The preferred way to construct a parameter specification is via the dedicated syntax\n\
for generic functions, classes, and type aliases, where\n\
the use of '**' creates a parameter specification:\n\
\n\
type IntFunc[**P] = Callable[P, int]\n\
\n\
For compatibility with Python 3.11 and earlier, ParamSpec objects\n\
can also be created as follows:\n\
\n\
P = ParamSpec('P')\n\
\n\
@ -952,12 +952,9 @@ callable to another callable, a pattern commonly found in higher order\n\
functions and decorators. They are only valid when used in ``Concatenate``,\n\
or as the first argument to ``Callable``, or as parameters for user-defined\n\
Generics. See class Generic for more information on generic types. An\n\
example for annotating a decorator::\n\
example for annotating a decorator:\n\
\n\
T = TypeVar('T')\n\
P = ParamSpec('P')\n\
\n\
def add_logging(f: Callable[P, T]) -> Callable[P, T]:\n\
def add_logging[**P, T](f: Callable[P, T]) -> Callable[P, T]:\n\
'''A type-safe decorator to add logging to a function.'''\n\
def inner(*args: P.args, **kwargs: P.kwargs) -> T:\n\
logging.info(f'{f.__name__} was called')\n\
@ -969,17 +966,9 @@ example for annotating a decorator::\n\
'''Add two numbers together.'''\n\
return x + y\n\
\n\
Parameter specification variables defined with covariant=True or\n\
contravariant=True can be used to declare covariant or contravariant\n\
generic types. These keyword arguments are valid, but their actual semantics\n\
are yet to be decided. See PEP 612 for details.\n\
\n\
Parameter specification variables can be introspected. e.g.:\n\
\n\
P.__name__ == 'P'\n\
P.__bound__ == None\n\
P.__covariant__ == False\n\
P.__contravariant__ == False\n\
\n\
Note that only parameter specification variables defined in global scope can\n\
be pickled.\n\
@ -1175,9 +1164,18 @@ static PyMethodDef typevartuple_methods[] = {
};
PyDoc_STRVAR(typevartuple_doc,
"Type variable tuple.\n\
"Type variable tuple. A specialized form of type variable that enables\n\
variadic generics.\n\
\n\
Usage:\n\
The preferred way to construct a type variable tuple is via the dedicated syntax\n\
for generic functions, classes, and type aliases, where a single\n\
'*' indicates a type variable tuple:\n\
\n\
def move_first_element_to_last[T, *Ts](tup: tuple[T, *Ts]) -> tuple[*Ts, T]:\n\
return (*tup[1:], tup[0])\n\
\n\
For compatibility with Python 3.11 and earlier, TypeVarTuple objects\n\
can also be created as follows:\n\
\n\
Ts = TypeVarTuple('Ts') # Can be given any name\n\
\n\
@ -1185,7 +1183,7 @@ Just as a TypeVar (type variable) is a placeholder for a single type,\n\
a TypeVarTuple is a placeholder for an *arbitrary* number of types. For\n\
example, if we define a generic class using a TypeVarTuple:\n\
\n\
class C(Generic[*Ts]): ...\n\
class C[*Ts]: ...\n\
\n\
Then we can parameterize that class with an arbitrary number of type\n\
arguments:\n\
@ -1441,6 +1439,23 @@ PyDoc_STRVAR(typealias_doc,
Type aliases are created through the type statement:\n\
\n\
type Alias = int\n\
\n\
In this example, Alias and int will be treated equivalently by static\n\
type checkers.\n\
\n\
At runtime, Alias is an instance of TypeAliasType. The __name__ attribute\n\
holds the name of the type alias. The value of the type\n\
alias is stored in the __value__ attribute. It is evaluated lazily, so\n\
the value is computed only if the attribute is accessed.\n\
\n\
Type aliases can also be generic:\n\
\n\
type ListOrSet[T] = list[T] | set[T]\n\
\n\
In this case, the type parameters of the alias are stored in the\n\
__type_params__ attribute.\n\
\n\
See PEP 695 for more information.\n\
");
static PyNumberMethods typealias_as_number = {
@ -1489,14 +1504,14 @@ PyDoc_STRVAR(generic_doc,
\n\
A generic type is typically declared by inheriting from\n\
this class parameterized with one or more type variables.\n\
For example, a generic mapping type might be defined as::\n\
For example, a generic mapping type might be defined as:\n\
\n\
class Mapping(Generic[KT, VT]):\n\
def __getitem__(self, key: KT) -> VT:\n\
...\n\
# Etc.\n\
\n\
This class can then be used as follows::\n\
This class can then be used as follows:\n\
\n\
def lookup_name(mapping: Mapping[KT, VT], key: KT, default: VT) -> VT:\n\
try:\n\