diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 5c50eff6393..1a6d70ec12e 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -659,6 +659,8 @@ peps/pep-0777.rst @warsaw # ... peps/pep-0779.rst @Yhg1s @colesbury @mpage # ... +peps/pep-0781.rst @methane +# ... peps/pep-0789.rst @njsmith # ... peps/pep-0801.rst @warsaw diff --git a/peps/pep-0781.rst b/peps/pep-0781.rst new file mode 100644 index 00000000000..4c4c796ee04 --- /dev/null +++ b/peps/pep-0781.rst @@ -0,0 +1,122 @@ +PEP: 781 +Title: Make ``TYPE_CHECKING`` a built-in constant +Author: Inada Naoki +Discussions-To: https://discuss.python.org/t/85728 +Status: Draft +Type: Standards Track +Topic: Typing +Created: 24-Mar-2025 +Python-Version: 3.14 +Post-History: `11-Jan-2025 `__, + `24-Mar-2025 `__, + + +Abstract +======== + +This PEP proposes adding a new built-in variable, :data:`!TYPE_CHECKING`, to +improve the experience of writing Python code with type annotations. It is +evaluated as ``True`` when the code is being analyzed by a static type checker, +and as ``False`` during normal runtime execution. Unlike +:data:`typing.TYPE_CHECKING`, which this variable replaces, it does not require +an import statement. + + +Motivation +========== + +Type annotations were defined for Python by :pep:`484`, and have enjoyed +widespread adoption. A challenge with fully-annotated code is that many +more imports are required in order to bring the relevant name into scope, +potentially causing import cycles without careful design. This has been +recognized by :pep:`563` and later :pep:`649`, which introduce two different +mechanisms for deferred evaluation of type annotations. As PEP 563 notes, +"type hints are ... not computationally free". The :data:`typing.TYPE_CHECKING` +constant was thus introduced__, initially to aid in breaking cyclic imports. + +__ https://github.com/python/typing/issues/230 + +In situations where startup time is critical, such as command-line interfaces, +applications, or core libraries, programmers may place all import statements +not required for runtime execution within a 'TYPE_CHECKING block', or even +defer certain imports to within functions. The ``typing`` module itself though +can take as much as 10ms to import, longer than Python takes to initialize. +The time taken to import the ``typing`` module clearly cannot be ignored. + +To avoid importing ``TYPE_CHECKING`` from ``typing``, developers currently +define a module-level variable such as ``TYPE_CHECKING = False`` or use code +like ``if False: # TYPE_CHECKING``. Providing a standard method will allow +many tools to implement the same behavior consistently. It will also allow +third-party tools in the ecosystem to standardize on a single behavior +with guaranteed semantics, as for example some static type checkers currently +do not permit local constants, only recognizing ``typing.TYPE_CHECKING``. + + +Specification +============= + +``TYPE_CHECKING`` is a built-in constant and its value is ``False``. +Unlike ``True``, ``False``, ``None``, and ``__debug__``, ``TYPE_CHECKING`` is +not a real constant; assigning to it will not raise a ``SyntaxError``. + +Static type checkers must treat ``TYPE_CHECKING`` as ``True``, similar to +:data:`typing.TYPE_CHECKING`. + +If this PEP is accepted, the new ``TYPE_CHECKING`` constant will be +the preferred approach, instead of the existing ``typing.TYPE_CHECKING``. +However, ``typing.TYPE_CHECKING`` will not be deprecated in the foreseeable +future. + + +Backwards Compatibility +======================= + +Since ``TYPE_CHECKING`` doesn't prohibit assignment, existing code using +``TYPE_CHECKING`` will continue to work. + +.. code-block:: python + + # This code will continue to work + TYPE_CHECKING = False + from typing import TYPE_CHECKING + + +User can remove the assignment to ``TYPE_CHECKING`` after they stop using +Python 3.13 or older versions. + + +How to Teach This +================= + +* Use ``if TYPE_CHECKING:`` for skipping type-checking code at runtime. +* Use ``from typing import TYPE_CHECKING`` to support Python versions before + 3.14. +* Workarounds like ``TYPE_CHECKING = False`` or ``if False: # TYPE_CHECKING`` + will continue to work, but are not recommended. + + +Reference Implementation +======================== + +* `python/cpython#131793 `__ + + +Rejected Ideas +============== + +Eliminate type-checking-only code +--------------------------------- + +It is considered to add real constant named ``__type_checking__`` +to eliminate type-checking-only code at compile time. + +However, adding real constant to language increase complexity of the language. +Benefit from eliminating type-checking-only code is estimated to be not enough +to justify the complexity. + + +Copyright +========= + +This document is placed in the public domain or under the +CC0-1.0-Universal license, whichever is more permissive.