TECH Signal 412
Python treats six pre-declared constants with inconsistent special cases
Illustration only Photo by Anton Savinov on Unsplash
Python's six pre-declared constants exhibit differing behaviors in syntax, mutability, and lexical handling
Engineers writing or debugging Python code may encounter unexpected syntax errors or attribute behaviors when interacting with these constants. The inconsistencies complicate language semantics and tooling that relies on uniform identifier resolution. Understanding these edge cases prevents subtle bugs in optimization or metaprogramming scenarios
Written by elseif from the cluster below · every claim links back to a sourceThe three things worth knowing
True, False, and None are lexical tokens, not identifiers, causing syntax errors in expressions like x.True
__debug__ is a mutable identifier in builtins but behaves as a constant in direct access, resisting assignment or deletion
Ellipsis and NotImplemented are regular builtins, shadowable by globals, unlike the other four constants
THE READ
What the cluster adds up to.
Python's six pre-declared constants are grouped in documentation but diverge sharply in implementation. True, False, and None are lexical tokens, parsed before name resolution, which prevents their use in attribute access expressions. This design choice isolates them from the rest of Python's identifier system, creating a unique category of syntax that behaves unlike any other language construct. The inconsistency surfaces in error handling, where attempts to use these tokens in invalid contexts raise SyntaxError rather than AttributeError or NameError.
The __debug__ constant occupies a middle ground between lexical tokens and regular identifiers. While it can be accessed as a builtin via getattr or setattr, direct assignment or deletion raises SyntaxError. This special-casing persists even when __debug__ is used as an attribute, where it triggers AttributeError instead of the expected NameError. The behavior becomes particularly confusing when running Python with -O, as the constant's value flips without any code changes, potentially altering program logic in optimization scenarios.
Ellipsis and NotImplemented stand apart from the other constants by functioning as ordinary builtins. They can be shadowed by global variables, unlike True, False, None, or __debug__, which resist reassignment. The distinction extends to the ... syntax for Ellipsis, which remains constant even when the Ellipsis builtin is overwritten. This creates a two-tier system where some constants are truly immutable while others are merely convention, complicating static analysis and refactoring tools that assume uniform behavior across builtins.
The inconsistencies manifest in edge cases that affect both runtime behavior and tooling. For example, syntax highlighters or linters must account for the special lexical status of True, False, and None, while code generators need to handle __debug__'s resistance to assignment. The varying error types, SyntaxError for some operations, AttributeError for others, force engineers to write defensive code that anticipates these quirks. These design choices, while individually justified, collectively increase the cognitive load of working with Python's constant system.
Written by elseif from the cluster below · checked for specifics the sources never containedTHE CLUSTER