diff --git a/peps/pep-0827.rst b/peps/pep-0827.rst index 60706edc894..3f4bf714c3a 100644 --- a/peps/pep-0827.rst +++ b/peps/pep-0827.rst @@ -8,7 +8,7 @@ Status: Draft Type: Standards Track Topic: Typing Created: 27-Feb-2026 -Python-Version: 3.15 +Python-Version: 3.16 Post-History: 02-Mar-2026 @@ -376,18 +376,39 @@ this PEP. We introduce a ``Param`` type that contains all the information about a function param:: - class Param[N: str | None, T, Q: ParamQuals = typing.Never]: + class Param[ + N: str | None, + T, + K: ParamKind = Literal["positional_or_keyword"], + D = typing.Never, + ]: pass - ParamQuals = typing.Literal["*", "**", "default", "keyword"] + ParamKind = typing.Literal[ + "*", "**", "keyword", "positional", "positional_or_keyword" + ] - type PosParam[N: str | None, T] = Param[N, T, Literal["positional"]] - type PosDefaultParam[N: str | None, T] = Param[N, T, Literal["positional", "default"]] - type DefaultParam[N: str, T] = Param[N, T, Literal["default"]] + type PosParam[T] = Param[None, T, Literal["positional"]] + type PosDefaultParam[T] = Param[None, T, Literal["positional"], T] + type DefaultParam[N: str, T] = Param[N, T, Literal["positional_or_keyword"], T] type NamedParam[N: str, T] = Param[N, T, Literal["keyword"]] - type NamedDefaultParam[N: str, T] = Param[N, T, Literal["keyword", "default"]] - type ArgsParam[T] = Param[Literal[None], T, Literal["*"]] - type KwargsParam[T] = Param[Literal[None], T, Literal["**"]] + type NamedDefaultParam[N: str, T] = Param[N, T, Literal["keyword"], T] + type ArgsParam[T] = Param[None, T, Literal["*"]] + type KwargsParam[T] = Param[None, T, Literal["**"]] + + +The argument ``K``, of type ``ParamKind``, represents the parameter +kind of the parameter, and defaults to the ordinary +``Literal["positional_or_keyword"]``. It is an error to create +``Callable`` with a ``Param`` containing multiple kinds unioned +together. + +The argument ``D`` carries the type of the parameter's default, if one +exists, and is ``Never`` otherwise. When the default value is a +literal (e.g. ``None``, an int, a string, an enum member), ``D`` may +be a ``Literal`` carrying that value. (Having it be such a ``Literal`` +has no effect other than to make it available to introspection and +potentially for diagnostics.) We also introduce a ``Params`` type that wraps a sequence of ``Param`` types, serving as the first argument to ``Callable``:: @@ -419,17 +440,18 @@ as:: Params[ Param[Literal["a"], int, Literal["positional"]], Param[Literal["b"], int], - Param[Literal["c"], int, Literal["default"]], + Param[Literal["c"], int, Literal["positional_or_keyword"], Literal[0]], Param[None, int, Literal["*"]], Param[Literal["d"], int, Literal["keyword"]], - Param[Literal["e"], int, Literal["default", "keyword"]], + Param[Literal["e"], int, Literal["keyword"], Literal[0]], Param[None, int, Literal["**"]], ], int, ] -or, using the type abbreviations we provide:: +or, using the type abbreviations we provide (though this version will not track +specific values for the defaults):: Callable[ Params[ @@ -793,8 +815,9 @@ Callable inspection and creation ``Callable`` types always have their arguments exposed in the extended Callable format discussed above. -The names, type, and qualifiers share associated type names with -``Member`` (``.name``, ``.type``, and ``.quals``). +The name and type associated type names with ``Member`` (``.name`` and +``.type``). ``Param`` also has a ``.kind`` associated type, which +exposes ``K`` and a ``.default`` associated type, which exposes ``D``. .. _pep827-generic-callable: @@ -1101,13 +1124,10 @@ based on iterating over all attributes. p.name, p.type, # All arguments are keyword-only - # It takes a default if a default is specified in the class - Literal["keyword"] - if typing.IsAssignable[ - GetDefault[p.init], - Never, - ] - else Literal["keyword", "default"], + Literal["keyword"], + # GetDefault is Never when there's no default, so use it + # directly as D. + GetDefault[p.init], ] for p in typing.Iter[typing.Attrs[T]] ], @@ -1343,7 +1363,7 @@ functions with explicit generic annotations. For old-style generics, we'll probably have to try to evaluate it and then raise an error when we encounter a variable.) -With our real syntax, this look likes:: +With our real syntax, this looks like:: type Foo = NewProtocol[ Member[ @@ -1888,10 +1908,6 @@ Open Issues would be to mirror ``inspect.Signature`` more directly, and have an enum with names like ``ParamKind.POSITIONAL_OR_KEYWORD``. Would that be better? - A related potential change would be to fully separate the kind from whether - there is a default, and have whether there is a default represented in - an ``init`` field, like we do for class member initializers with ``Member``. - * :ref:`Members `: Should ``Members`` return all methods, even those without annotations? We excluded them out of the desire for some consistency with attributes, but it would not be