PEP 661: Proposed typing specification changes (#4065)
This is an attempt to specify the behavior that I suggested on Discuss and that has been endorsed by the Typing Council. Co-authored-by: Tal Einat <532281+taleinat@users.noreply.github.com>
This commit is contained in:
parent
8ae21fff71
commit
1c213ece4b
|
@ -177,12 +177,6 @@ with the same name in different modules will be distinct from each other.
|
||||||
Creating a copy of a sentinel object, such as by using ``copy.copy()`` or by
|
Creating a copy of a sentinel object, such as by using ``copy.copy()`` or by
|
||||||
pickling and unpickling, will return the same object.
|
pickling and unpickling, will return the same object.
|
||||||
|
|
||||||
Type annotations for sentinel values should use ``Literal[<sentinel_object>]``.
|
|
||||||
For example::
|
|
||||||
|
|
||||||
def foo(value: int | Literal[MISSING] = MISSING) -> int:
|
|
||||||
...
|
|
||||||
|
|
||||||
The ``module_name`` optional argument should normally not need to be supplied,
|
The ``module_name`` optional argument should normally not need to be supplied,
|
||||||
as ``Sentinel()`` will usually be able to recognize the module in which it was
|
as ``Sentinel()`` will usually be able to recognize the module in which it was
|
||||||
called. ``module_name`` should be supplied only in unusual cases when this
|
called. ``module_name`` should be supplied only in unusual cases when this
|
||||||
|
@ -197,6 +191,51 @@ add minimal complexity.
|
||||||
|
|
||||||
Ordering comparisons are undefined for sentinel objects.
|
Ordering comparisons are undefined for sentinel objects.
|
||||||
|
|
||||||
|
Typing
|
||||||
|
------
|
||||||
|
|
||||||
|
To make usage of sentinels clear and simple in typed Python code, we propose to
|
||||||
|
amend the type system with a special case for sentinel objects.
|
||||||
|
|
||||||
|
Sentinel objects may be used in
|
||||||
|
:term:`type expressions <typing:type expression>`, representing themselves.
|
||||||
|
This is similar to how ``None`` is handled in the existing type system. For
|
||||||
|
example::
|
||||||
|
|
||||||
|
from sentinels import Sentinel
|
||||||
|
|
||||||
|
MISSING = Sentinel('MISSING')
|
||||||
|
|
||||||
|
def foo(value: int | MISSING = MISSING) -> int:
|
||||||
|
...
|
||||||
|
|
||||||
|
More formally, type checkers should recognize sentinel creations of the form
|
||||||
|
``NAME = Sentinel('NAME')`` as creating a new sentinel object. If the name
|
||||||
|
passed to the ``Sentinel`` constructor does not match the name the object is
|
||||||
|
assigned to, type checkers should emit an error.
|
||||||
|
|
||||||
|
Sentinels defined using this syntax may be used in
|
||||||
|
:term:`type expressions <typing:type expression>`. They
|
||||||
|
represent a :term:`fully static type <typing:fully static type>` that has a
|
||||||
|
single member, the sentinel object itself.
|
||||||
|
|
||||||
|
Type checkers should support narrowing union types involving sentinels
|
||||||
|
using the ``is`` and ``is not`` operators::
|
||||||
|
|
||||||
|
from sentinels import Sentinel
|
||||||
|
from typing import assert_type
|
||||||
|
|
||||||
|
MISSING = Sentinel('MISSING')
|
||||||
|
|
||||||
|
def foo(value: int | MISSING) -> None:
|
||||||
|
if value is MISSING:
|
||||||
|
assert_type(value, MISSING)
|
||||||
|
else:
|
||||||
|
assert_type(value, int)
|
||||||
|
|
||||||
|
To support usage in type expressions, the runtime implementation
|
||||||
|
of the ``Sentinel`` class should have the ``__or__`` and ``__ror__``
|
||||||
|
methods, returning :py:class:`typing.Union` objects.
|
||||||
|
|
||||||
Backwards Compatibility
|
Backwards Compatibility
|
||||||
=======================
|
=======================
|
||||||
|
|
Loading…
Reference in New Issue