summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorJelle Zijlstra <jelle.zijlstra@gmail.com>2023-05-26 17:48:17 (GMT)
committerGitHub <noreply@github.com>2023-05-26 17:48:17 (GMT)
commit060277d96bf4ba86df8e4d65831a8cbdfeb51fc5 (patch)
treedfd0d01dc2eec83844458f368d6a0997ec0e18b8 /Objects
parent95f1b1fef777254a45559c0348e80185df3634ff (diff)
downloadcpython-060277d96bf4ba86df8e4d65831a8cbdfeb51fc5.zip
cpython-060277d96bf4ba86df8e4d65831a8cbdfeb51fc5.tar.gz
cpython-060277d96bf4ba86df8e4d65831a8cbdfeb51fc5.tar.bz2
gh-103921: Document PEP 695 (#104642)
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
Diffstat (limited to 'Objects')
-rw-r--r--Objects/typevarobject.c115
1 files changed, 65 insertions, 50 deletions
diff --git a/Objects/typevarobject.c b/Objects/typevarobject.c
index 6aa0d8a..0b7d84c 100644
--- a/Objects/typevarobject.c
+++ b/Objects/typevarobject.c
@@ -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\
-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\
-\n\
- def repeat(x: T, n: int) -> List[T]:\n\
- '''Return a list containing n references to x.'''\n\
- return [x]*n\n\
+This syntax can also be used to create bound and constrained type\n\
+variables:\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\
+ class StrSequence[S: str]: # S is a TypeVar bound to str\n\
+ ...\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\
+ class StrOrBytesSequence[A: (str, bytes)]: # A is a TypeVar constrained to str or bytes\n\
+ ...\n\
\n\
-At runtime, isinstance(x, T) and issubclass(C, T) will raise TypeError.\n\
+However, if desired, reusable type variables can also be constructed\n\
+manually, like so:\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\
+ 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 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\
+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 and type alias definitions.\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\
-\n\
- T = TypeVar('T')\n\
- P = ParamSpec('P')\n\
+example for annotating a decorator:\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\
+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\
-Usage:\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\