PEP 696: Replace usages of TypeVarLike with type parameter (#3619)
Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
This commit is contained in:
parent
e31c0d565e
commit
27ed905918
|
@ -1,5 +1,5 @@
|
||||||
PEP: 696
|
PEP: 696
|
||||||
Title: Type defaults for TypeVarLikes
|
Title: Type Defaults for Type Parameters
|
||||||
Author: James Hilton-Balfe <gobot1234yt@gmail.com>
|
Author: James Hilton-Balfe <gobot1234yt@gmail.com>
|
||||||
Sponsor: Jelle Zijlstra <jelle.zijlstra@gmail.com>
|
Sponsor: Jelle Zijlstra <jelle.zijlstra@gmail.com>
|
||||||
Discussions-To: https://discuss.python.org/t/pep-696-type-defaults-for-typevarlikes/22569
|
Discussions-To: https://discuss.python.org/t/pep-696-type-defaults-for-typevarlikes/22569
|
||||||
|
@ -15,8 +15,8 @@ Post-History: `22-Mar-2022 <https://mail.python.org/archives/list/typing-sig@pyt
|
||||||
Abstract
|
Abstract
|
||||||
--------
|
--------
|
||||||
|
|
||||||
This PEP introduces the concept of type defaults for
|
This PEP introduces the concept of type defaults for type parameters,
|
||||||
``TypeVarLike``\ s (``TypeVar``, ``ParamSpec`` and ``TypeVarTuple``),
|
including ``TypeVar``, ``ParamSpec``, and ``TypeVarTuple``,
|
||||||
which act as defaults for a type parameter when one is not specified or
|
which act as defaults for a type parameter when one is not specified or
|
||||||
the constraint solver isn't able to solve a type parameter to anything.
|
the constraint solver isn't able to solve a type parameter to anything.
|
||||||
|
|
||||||
|
@ -93,7 +93,7 @@ Default Ordering and Subscription Rules
|
||||||
'''''''''''''''''''''''''''''''''''''''
|
'''''''''''''''''''''''''''''''''''''''
|
||||||
|
|
||||||
The order for defaults should follow the standard function parameter
|
The order for defaults should follow the standard function parameter
|
||||||
rules, so a ``TypeVarLike`` with no ``default`` cannot follow one with
|
rules, so a type parameter with no ``default`` cannot follow one with
|
||||||
a ``default`` value. Doing so should ideally raise a ``TypeError`` in
|
a ``default`` value. Doing so should ideally raise a ``TypeError`` in
|
||||||
``typing._GenericAlias``/``types.GenericAlias``, and a type checker
|
``typing._GenericAlias``/``types.GenericAlias``, and a type checker
|
||||||
should flag this an error.
|
should flag this an error.
|
||||||
|
@ -175,15 +175,15 @@ or another in-scope ``TypeVarTuple`` (see `Scoping Rules`_).
|
||||||
reveal_type(Foo()) # type is Foo[str, int]
|
reveal_type(Foo()) # type is Foo[str, int]
|
||||||
reveal_type(Foo[int, bool]()) # type is Foo[int, bool]
|
reveal_type(Foo[int, bool]()) # type is Foo[int, bool]
|
||||||
|
|
||||||
Using Another ``TypeVarLike`` as ``default``
|
Using Another Type Parameter as ``default``
|
||||||
''''''''''''''''''''''''''''''''''''''''''''
|
''''''''''''''''''''''''''''''''''''''''''''
|
||||||
|
|
||||||
This allows for a value to be used again when the constraints solver
|
This allows for a value to be used again when the constraints solver
|
||||||
fails to solve a constraint for a type, or the type parameter to a
|
fails to solve a constraint for a type, or the type parameter to a
|
||||||
generic is missing but another type parameter is specified.
|
generic is missing but another type parameter is specified.
|
||||||
|
|
||||||
To use another ``TypeVarLike`` as a default the ``default`` and the
|
To use another type parameter as a default the ``default`` and the
|
||||||
``TypeVarLike`` must be the same type (a ``TypeVar``'s default must be
|
type parameter must be the same type (a ``TypeVar``'s default must be
|
||||||
a ``TypeVar``, etc.).
|
a ``TypeVar``, etc.).
|
||||||
|
|
||||||
`This could be used on builtins.slice <https://github.com/python/typing/issues/159>`__
|
`This could be used on builtins.slice <https://github.com/python/typing/issues/159>`__
|
||||||
|
@ -212,17 +212,17 @@ default to the type of ``start`` and step default to ``int | None``.
|
||||||
Foo[int](1, "") # Invalid: Foo[int, str] cannot be assigned to self: Foo[int, int] in Foo.__init__
|
Foo[int](1, "") # Invalid: Foo[int, str] cannot be assigned to self: Foo[int, int] in Foo.__init__
|
||||||
Foo[int]("", 1) # Invalid: Foo[str, int] cannot be assigned to self: Foo[int, int] in Foo.__init__
|
Foo[int]("", 1) # Invalid: Foo[str, int] cannot be assigned to self: Foo[int, int] in Foo.__init__
|
||||||
|
|
||||||
When using a ``TypeVarLike`` as the default to another ``TypeVarLike``.
|
When using a type parameter as the default to another type parameter.
|
||||||
Where ``T1`` is the default for ``T2`` the following rules apply.
|
Where ``T1`` is the default for ``T2`` the following rules apply.
|
||||||
|
|
||||||
``TypeVarTuple``\s are not supported because:
|
``TypeVarTuple``\s are not supported because:
|
||||||
|
|
||||||
- `Scoping Rules`_ does not allow usage of ``TypeVarLikes``
|
- `Scoping Rules`_ does not allow usage of type parameters
|
||||||
from outer scopes.
|
from outer scopes.
|
||||||
- Multiple ``TypeVarTuple``\s cannot appear in the type
|
- Multiple ``TypeVarTuple``\s cannot appear in the type
|
||||||
parameter list for a single class, as specified in
|
parameter list for a single class, as specified in
|
||||||
:pep:`646#multiple-type-variable-tuples-not-allowed`.
|
:pep:`646#multiple-type-variable-tuples-not-allowed`.
|
||||||
- ``TypeVarLike`` defaults in functions are not supported.
|
- type parameter defaults in functions are not supported.
|
||||||
|
|
||||||
These reasons leave no current valid location where a
|
These reasons leave no current valid location where a
|
||||||
``TypeVarTuple`` could have a default.
|
``TypeVarTuple`` could have a default.
|
||||||
|
@ -245,7 +245,7 @@ Scoping Rules
|
||||||
class slice(Generic[StartT, StopT, StepT]): ...
|
class slice(Generic[StartT, StopT, StepT]): ...
|
||||||
# ^^^^^^ Invalid: ordering does not allow StopT to be bound
|
# ^^^^^^ Invalid: ordering does not allow StopT to be bound
|
||||||
|
|
||||||
Using a ``TypeVarLike`` from an outer scope as a default is not supported.
|
Using a type parameter from an outer scope as a default is not supported.
|
||||||
|
|
||||||
Bound Rules
|
Bound Rules
|
||||||
~~~~~~~~~~~
|
~~~~~~~~~~~
|
||||||
|
@ -274,10 +274,10 @@ The constraints of ``T2`` must be a superset of the constraints of ``T1``.
|
||||||
TypeVar("AlsoInvalid", bool, complex, default=T1) # Invalid: {bool, complex} is not a superset of {int, str}
|
TypeVar("AlsoInvalid", bool, complex, default=T1) # Invalid: {bool, complex} is not a superset of {int, str}
|
||||||
|
|
||||||
|
|
||||||
``TypeVarLike``\s as Parameters to Generics
|
Type Parameters as Parameters to Generics
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
``TypeVarLike``\ s are valid as parameters to generics inside of a
|
Type parameters are valid as parameters to generics inside of a
|
||||||
``default`` when the first parameter is in scope as determined by the
|
``default`` when the first parameter is in scope as determined by the
|
||||||
`previous section <scoping rules_>`_.
|
`previous section <scoping rules_>`_.
|
||||||
|
|
||||||
|
@ -298,7 +298,7 @@ The constraints of ``T2`` must be a superset of the constraints of ``T1``.
|
||||||
Specialisation Rules
|
Specialisation Rules
|
||||||
~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
``TypeVarLike``\ s currently cannot be further subscripted. This might
|
Type parameters currently cannot be further subscripted. This might
|
||||||
change if `Higher Kinded TypeVars <https://github.com/python/typing/issues/548>`__
|
change if `Higher Kinded TypeVars <https://github.com/python/typing/issues/548>`__
|
||||||
are implemented.
|
are implemented.
|
||||||
|
|
||||||
|
@ -307,7 +307,7 @@ are implemented.
|
||||||
'''''''''''''''''''''''''''''
|
'''''''''''''''''''''''''''''
|
||||||
|
|
||||||
``Generic`` ``TypeAlias``\ es should be able to be further subscripted
|
``Generic`` ``TypeAlias``\ es should be able to be further subscripted
|
||||||
following normal subscription rules. If a ``TypeVarLike`` has a default
|
following normal subscription rules. If a type parameter has a default
|
||||||
that hasn't been overridden it should be treated like it was
|
that hasn't been overridden it should be treated like it was
|
||||||
substituted into the ``TypeAlias``. However, it can be specialised
|
substituted into the ``TypeAlias``. However, it can be specialised
|
||||||
further down the line.
|
further down the line.
|
||||||
|
@ -325,7 +325,7 @@ further down the line.
|
||||||
Subclassing
|
Subclassing
|
||||||
'''''''''''
|
'''''''''''
|
||||||
|
|
||||||
Subclasses of ``Generic``\ s with ``TypeVarLike``\ s that have defaults
|
Subclasses of ``Generic``\ s with type parameters that have defaults
|
||||||
behave similarly to ``Generic`` ``TypeAlias``\ es.
|
behave similarly to ``Generic`` ``TypeAlias``\ es.
|
||||||
|
|
||||||
.. code-block:: py
|
.. code-block:: py
|
||||||
|
@ -378,14 +378,14 @@ subtype of one of the constraints.
|
||||||
Function Defaults
|
Function Defaults
|
||||||
'''''''''''''''''
|
'''''''''''''''''
|
||||||
|
|
||||||
``TypeVarLike``\ s currently are not supported in the signatures of
|
Type parameters currently are not supported in the signatures of
|
||||||
functions as ensuring the ``default`` is returned in every code path
|
functions as ensuring the ``default`` is returned in every code path
|
||||||
where the ``TypeVarLike`` can go unsolved is too hard to implement.
|
where the type parameter can go unsolved is too hard to implement.
|
||||||
|
|
||||||
Binding rules
|
Binding rules
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
``TypeVarLikes`` defaults should be bound by attribute access
|
Type parameter defaults should be bound by attribute access
|
||||||
(including call and subscript).
|
(including call and subscript).
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
@ -469,14 +469,14 @@ Grammar Changes
|
||||||
| '=' e=expression
|
| '=' e=expression
|
||||||
| '=' e=starred_expression
|
| '=' e=starred_expression
|
||||||
|
|
||||||
This would mean that ``TypeVarLike``\ s with defaults proceeding those
|
This would mean that type parameters with defaults proceeding those
|
||||||
with non-defaults can be checked at compile time.
|
with non-defaults can be checked at compile time.
|
||||||
|
|
||||||
|
|
||||||
Rejected Alternatives
|
Rejected Alternatives
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
Allowing the ``TypeVarLike``\s Defaults to Be Passed to ``type.__new__``'s ``**kwargs``
|
Allowing the Type Parameters Defaults to Be Passed to ``type.__new__``'s ``**kwargs``
|
||||||
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
|
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
|
||||||
|
|
||||||
.. code-block:: py
|
.. code-block:: py
|
||||||
|
@ -535,8 +535,8 @@ Having ``default`` Implicitly Be ``bound``
|
||||||
|
|
||||||
In an earlier version of this PEP, the ``default`` was implicitly set
|
In an earlier version of this PEP, the ``default`` was implicitly set
|
||||||
to ``bound`` if no value was passed for ``default``. This while
|
to ``bound`` if no value was passed for ``default``. This while
|
||||||
convenient, could have a ``TypeVarLike`` with no default follow a
|
convenient, could have a type parameter with no default follow a
|
||||||
``TypeVarLike`` with a default. Consider:
|
type parameter with a default. Consider:
|
||||||
|
|
||||||
.. code-block:: py
|
.. code-block:: py
|
||||||
|
|
||||||
|
@ -557,7 +557,7 @@ convenient, could have a ``TypeVarLike`` with no default follow a
|
||||||
This would have also been a breaking change for a small number of cases
|
This would have also been a breaking change for a small number of cases
|
||||||
where the code relied on ``Any`` being the implicit default.
|
where the code relied on ``Any`` being the implicit default.
|
||||||
|
|
||||||
Allowing ``TypeVarLike``\s with defaults to be used in function signatures
|
Allowing Type Parameters With Defaults To Be Used in Function Signatures
|
||||||
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
|
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
|
||||||
|
|
||||||
A previous version of this PEP allowed ``TypeVarLike``\s with defaults to be used in
|
A previous version of this PEP allowed ``TypeVarLike``\s with defaults to be used in
|
||||||
|
@ -565,7 +565,7 @@ function signatures. This was removed for the reasons described in
|
||||||
`Function Defaults`_. Hopefully, this can be added in the future if
|
`Function Defaults`_. Hopefully, this can be added in the future if
|
||||||
a way to get the runtime value of a type parameter is added.
|
a way to get the runtime value of a type parameter is added.
|
||||||
|
|
||||||
Allowing ``TypeVarLikes`` from outer scopes in ``default``
|
Allowing Type Parameters from Outer Scopes in ``default``
|
||||||
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
|
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
|
||||||
|
|
||||||
This was deemed too niche a feature to be worth the added complexity.
|
This was deemed too niche a feature to be worth the added complexity.
|
||||||
|
|
Loading…
Reference in New Issue