diff options
author | Jelle Zijlstra <jelle.zijlstra@gmail.com> | 2023-05-26 17:48:17 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-05-26 17:48:17 (GMT) |
commit | 060277d96bf4ba86df8e4d65831a8cbdfeb51fc5 (patch) | |
tree | dfd0d01dc2eec83844458f368d6a0997ec0e18b8 /Objects | |
parent | 95f1b1fef777254a45559c0348e80185df3634ff (diff) | |
download | cpython-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.c | 115 |
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\ |