Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 42 additions & 26 deletions peps/pep-0827.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down Expand Up @@ -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``::
Expand Down Expand Up @@ -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)::
Comment thread
msullivan marked this conversation as resolved.

Callable[
Params[
Expand Down Expand Up @@ -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:

Expand Down Expand Up @@ -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]]
],
Expand Down Expand Up @@ -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[
Expand Down Expand Up @@ -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 <pep827-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
Expand Down
Loading