@@ -8,7 +8,7 @@ Status: Draft
88Type: Standards Track
99Topic: Typing
1010Created: 27-Feb-2026
11- Python-Version: 3.15
11+ Python-Version: 3.16
1212Post-History: 02-Mar-2026
1313
1414
@@ -376,18 +376,39 @@ this PEP.
376376
377377We introduce a ``Param `` type that contains all the information about a function param::
378378
379- class Param[N: str | None, T, Q: ParamQuals = typing.Never]:
379+ class Param[
380+ N: str | None,
381+ T,
382+ K: ParamKind = Literal["positional_or_keyword"],
383+ D = typing.Never,
384+ ]:
380385 pass
381386
382- ParamQuals = typing.Literal["*", "**", "default", "keyword"]
387+ ParamKind = typing.Literal[
388+ "*", "**", "keyword", "positional", "positional_or_keyword"
389+ ]
383390
384- type PosParam[N: str | None, T] = Param[N , T, Literal["positional"]]
385- type PosDefaultParam[N: str | None, T] = Param[N , T, Literal["positional", "default"] ]
386- type DefaultParam[N: str, T] = Param[N, T, Literal["default"] ]
391+ type PosParam[T] = Param[None , T, Literal["positional"]]
392+ type PosDefaultParam[T] = Param[None , T, Literal["positional"], T ]
393+ type DefaultParam[N: str, T] = Param[N, T, Literal["positional_or_keyword"], T ]
387394 type NamedParam[N: str, T] = Param[N, T, Literal["keyword"]]
388- type NamedDefaultParam[N: str, T] = Param[N, T, Literal["keyword", "default"]]
389- type ArgsParam[T] = Param[Literal[None], T, Literal["*"]]
390- type KwargsParam[T] = Param[Literal[None], T, Literal["**"]]
395+ type NamedDefaultParam[N: str, T] = Param[N, T, Literal["keyword"], T]
396+ type ArgsParam[T] = Param[None, T, Literal["*"]]
397+ type KwargsParam[T] = Param[None, T, Literal["**"]]
398+
399+
400+ The argument ``K ``, of type ``ParamKind ``, represents the parameter
401+ kind of the parameter, and defaults to the ordinary
402+ ``Literal["positional_or_keyword"] ``. It is an error to create
403+ ``Callable `` with a ``Param `` containing multiple kinds unioned
404+ together.
405+
406+ The argument ``D `` carries the type of the parameter's default, if one
407+ exists, and is ``Never `` otherwise. When the default value is a
408+ literal (e.g. ``None ``, an int, a string, an enum member), ``D `` may
409+ be a ``Literal `` carrying that value. (Having it be such a ``Literal ``
410+ has no effect other than to make it available to introspection and
411+ potentially for diagnostics.)
391412
392413We also introduce a ``Params `` type that wraps a sequence of ``Param ``
393414types, serving as the first argument to ``Callable ``::
@@ -419,17 +440,18 @@ as::
419440 Params[
420441 Param[Literal["a"], int, Literal["positional"]],
421442 Param[Literal["b"], int],
422- Param[Literal["c"], int, Literal["default" ]],
443+ Param[Literal["c"], int, Literal["positional_or_keyword"], Literal[0 ]],
423444 Param[None, int, Literal["*"]],
424445 Param[Literal["d"], int, Literal["keyword"]],
425- Param[Literal["e"], int, Literal["default", "keyword" ]],
446+ Param[Literal["e"], int, Literal["keyword"], Literal[0 ]],
426447 Param[None, int, Literal["**"]],
427448 ],
428449 int,
429450 ]
430451
431452
432- or, using the type abbreviations we provide::
453+ or, using the type abbreviations we provide (though this version will not track
454+ specific values for the defaults)::
433455
434456 Callable[
435457 Params[
@@ -793,8 +815,9 @@ Callable inspection and creation
793815``Callable `` types always have their arguments exposed in the extended
794816Callable format discussed above.
795817
796- The names, type, and qualifiers share associated type names with
797- ``Member `` (``.name ``, ``.type ``, and ``.quals ``).
818+ The name and type associated type names with ``Member `` (``.name `` and
819+ ``.type ``). ``Param `` also has a ``.kind `` associated type, which
820+ exposes ``K `` and a ``.default `` associated type, which exposes ``D ``.
798821
799822.. _pep827-generic-callable :
800823
@@ -1101,13 +1124,10 @@ based on iterating over all attributes.
11011124 p.name,
11021125 p.type,
11031126 # All arguments are keyword-only
1104- # It takes a default if a default is specified in the class
1105- Literal["keyword"]
1106- if typing.IsAssignable[
1107- GetDefault[p.init],
1108- Never,
1109- ]
1110- else Literal["keyword", "default"],
1127+ Literal["keyword"],
1128+ # GetDefault is Never when there's no default, so use it
1129+ # directly as D.
1130+ GetDefault[p.init],
11111131 ]
11121132 for p in typing.Iter[typing.Attrs[T]]
11131133 ],
@@ -1343,7 +1363,7 @@ functions with explicit generic annotations. For old-style generics,
13431363we'll probably have to try to evaluate it and then raise an error when
13441364we encounter a variable.)
13451365
1346- With our real syntax, this look likes ::
1366+ With our real syntax, this looks like ::
13471367
13481368 type Foo = NewProtocol[
13491369 Member[
@@ -1888,10 +1908,6 @@ Open Issues
18881908 would be to mirror ``inspect.Signature `` more directly, and have an enum
18891909 with names like ``ParamKind.POSITIONAL_OR_KEYWORD ``. Would that be better?
18901910
1891- A related potential change would be to fully separate the kind from whether
1892- there is a default, and have whether there is a default represented in
1893- an ``init `` field, like we do for class member initializers with ``Member ``.
1894-
18951911* :ref: `Members <pep827-members >`: Should ``Members `` return all
18961912 methods, even those without annotations? We excluded them out of the
18971913 desire for some consistency with attributes, but it would not be
0 commit comments