11PEP: 781
2- Title: Adding __type_checking__ constant
2+ Title: Making `` TYPE_CHECKING `` builtin
33Author: Inada Naoki <songofacandy@gmail.com>
44Discussions-To: https://discuss.python.org/t/85728
55Status: Draft
@@ -14,12 +14,11 @@ Post-History: `11-Jan-2025 <https://discuss.python.org/t/76766>`__,
1414Abstract
1515========
1616
17- This PEP proposes adding a new keyword , :data: `!__type_checking__ `, to improve
17+ This PEP proposes adding a new builtin , :data: `!TYPE_CHECKING `, to improve
1818the experience of writing Python code with type annotations. It is evaluated
1919as ``True `` when the code is being analyzed by a static type checker, and as
2020``False `` during normal runtime execution. Unlike :data: `typing.TYPE_CHECKING `,
21- which this keyword replaces, it does not require an import statement, and
22- creates the opportunity for compiler optimizations, such as smaller bytecode.
21+ which this keyword replaces, it does not require an import statement.
2322
2423
2524Motivation
@@ -30,7 +29,7 @@ widespread adoption. A challenge with fully-annotated code is that many
3029more imports are required in order to bring the relevant name into scope,
3130potentially causing import cycles without careful design. This has been
3231recognized by :pep: `563 ` and later :pep: `649 `, which introduce two different
33- mechanisms for deferred evaluation of type annotations. As PEP 563 notes,
32+ mechanisms for deferred evaluation of type annotations. As :pep: ` 563 ` notes,
3433"type hints are ... not computationally free". The :data: `typing.TYPE_CHECKING `
3534constant was thus introduced __, initially to aid in breaking cyclic imports.
3635
@@ -51,62 +50,67 @@ third-party tools in the ecosystem to standardize on a single behavior
5150with guaranteed semantics, as for example some static type checkers currently
5251do not permit local constants, only recognizing ``typing.TYPE_CHECKING ``.
5352
54- Furthermore, this allows compilers to eliminate type-checking-only code at
55- compile time, as the constant is guaranteed to be ``False `` and cannot be
56- reassigned. This reduces bytecode size and memory usage, and would help with
57- writing type-annotated code for memory-constrained environments such as WASM
58- or MicroPython.
5953
54+ Specification
55+ =============
6056
61- Rationale
62- =========
57+ ``TYPE_CHECKING `` is a built-in constant and its value is ``False ``.
58+ Unlike ``True ``, ``False ``, ``None ``, and ``__debug__ ``, ``TYPE_CHECKING `` is
59+ not a real constant; assigning to it will not raise a ``SyntaxError ``.
6360
64- Using Keyword
65- -------------
61+ Static type checkers must treat `` TYPE_CHECKING `` as `` True ``, similar to
62+ :data: ` typing.TYPE_CHECKING `.
6663
67- Avoiding the addition of a new :ref: `keyword <python:keywords >`
68- (like :data: `__debug__ `) would be attractive because more keywords means
69- a more complex language.
64+ If this PEP is accepted, the new ``TYPE_CHECKING `` constant will be
65+ the preferred approach, instead of the existing ``typing.TYPE_CHECKING ``.
66+ However, ``typing.TYPE_CHECKING `` will not be deprecated in the foreseeable
67+ future.
7068
71- However, adding a constant without a keyword (like :data: `__debug__ `) requires
72- special handling in both the compiler and runtime.
7369
74- By implementing ``__type_checking__ `` the same way as ``False ``, we avoid the
75- need for the special handling.
76- Therefore, making it a keyword is the simpler approach.
70+ Backwards Compatibility
71+ =======================
7772
73+ Since ``TYPE_CHECKING `` doesn't prohibit assignment, existing code using
74+ ``TYPE_CHECKING `` will continue to work.
7875
79- Specification
80- =============
76+ .. code-block :: python
8177
82- ``__type_checking__ `` is a :ref: `keyword <python:keywords >` and its value is
83- ``False ``.
84- It can be used in the same way as ``False ``, except it cannot be used as
85- a matching pattern.
78+ # These code will work as before
79+ TYPE_CHECKING = False
80+ from typing import TYPE_CHECKING
8681
87- Static type checkers must treat ``__type_checking__ `` as ``True ``,
88- similar to :data: `typing.TYPE_CHECKING `.
8982
90- If this PEP is accepted, ``__type_checking__ `` will be the preferred approach,
91- instead of ``typing.TYPE_CHECKING ``. However, ``typing.TYPE_CHECKING `` will not
92- be deprecated.
93- Instead, it will be implemented as ``TYPE_CHECKING = __type_checking__ ``,
94- allowing future type checkers to focus on only handling ``__type_checking__ ``.
83+ User can remove the assingment to ``TYPE_CHECKING `` after they stop using
84+ Python before 3.14.
9585
9686
9787How to Teach This
9888=================
9989
100- * Use ``__type_checking__ `` for skipping type-checking code at runtime.
101- * Use :data: ` typing. TYPE_CHECKING ` to support Python versions before 3.14.
90+ * Use ``if TYPE_CHECKING: `` for skipping type-checking code at runtime.
91+ * Use `` from typing import TYPE_CHECKING` ` to support Python versions before 3.14.
10292* Workarounds like ``TYPE_CHECKING = False `` or ``if False: # TYPE_CHECKING ``
103- are not recommended since Python 3.14 .
93+ are continued to work, but not recommended .
10494
10595
10696Reference Implementation
10797========================
10898
109- * `python/cpython#131641 <https://github.com/python/cpython/pull/131641 >`__
99+ * `python/cpython#131793 <https://github.com/python/cpython/pull/131793 >`__
100+
101+
102+ Rejected Ideas
103+ ==============
104+
105+ Eliminate type-checking-only Code
106+ ---------------------------------
107+
108+ It is considered to add real constant named ``__type_checking__ ``
109+ to eliminate type-checking-only code at compile time.
110+
111+ However, adding real constant to language increase complexity of the language.
112+ Benefit from eliminating type-checking-only code is estimated to be not enough
113+ to justify the complexity.
110114
111115
112116Copyright
0 commit comments