Python's pre-declared constants are kinda weird

Python’s handling of built-in constants like `True`, `False`, `None`, `Ellipsis`, and `__debug__` exposes some surprising edge cases, such as conditional code being stripped at compile time or historical quirks like reassigning booleans in early versions. Commenters use these examples to probe broader design trade-offs in Python: its accumulated “baggage,” odd corners of the type and async systems, and notoriously messy packaging, versus its strengths as an accessible, batteries-included language with a powerful ecosystem for scripting, data work, and glue code. The exchange also contrasts Python with languages like PHP, JavaScript, Ruby, and Haskell, highlighting recurring tensions between theoretical language elegance, backward compatibility, and pragmatic usability at scale.

Special constants and conditional compilation

  • Discussion centers on Python’s “pre-declared constants”: True, False, None (keywords) vs Ellipsis, NotImplemented, __debug__ (identifiers with special treatment).
  • __debug__ is highlighted as especially odd: if __debug__: blocks are compiled out entirely under PYTHONOPTIMIZE / -O, making it a form of conditional compilation together with assert.
  • This is why assigning to __debug__ is forbidden: the compiler assumes it is constant when eliminating code.
  • Several commenters admit they’d never heard of __debug__, or of its interaction with assert, and note the potential for real security bugs when assert is (mis)used for critical checks.
  • Upcoming TYPE_CHECKING in 3.15 is mentioned as another pre-declared constant behaving like Ellipsis/NotImplemented.

Historical quirks of booleans and design “baggage”

  • Early Python had no True/False; users defined them as 1/0. Python 2 allowed reassigning them; Python 3 turned them into keywords.
  • bool is still a subclass of int, which continues to surprise people and has caused bugs.
  • Broader point: retrofitting bool/null into a language is hard; C and Python are cited as examples.
  • Some discuss broader language-design regrets: lack of built-in multidimensional arrays, bit arrays, and standardized small vector types.

Python vs other languages and evolution

  • One camp argues Python is old, slow, brittle, with weak typing and chaotic packaging; they claim communities like PHP’s have evolved more aggressively and learned better lessons (e.g., enforced types, unified tooling).
  • Others list substantial Python improvements: type hints, async/await, performance work, f-strings, pattern matching, dict merge operators, dataclasses, GIL removal work, pathlib, etc.
  • A critical view holds that these features often copy ideas without key semantics (non-enforced types, non-exhaustive pattern matching, async “function coloring”), calling them “anti-features”.
  • Comparisons with JavaScript, PHP, Ruby, Racket/Scheme/Haskell are frequent; opinions vary on which is “weirder,” more consistent, or more beginner-friendly.

Beginner-friendliness and usage niches

  • Some say Python is too full of edge cases to be a good first language; others argue its REPL, batteries-included stdlib, readability, and Windows support make it an excellent teaching and “glue” language.
  • Significant indentation, truthiness, and duck typing are called “weird” by some, “consistent and learnable” by others.

Ecosystem, packaging, and imports

  • Many complaints about dependency management, virtualenvs, and fragmented tooling; uv is praised as a big improvement but not yet standard.
  • Import semantics (__name__ == "__main__", packages vs filesystem, __init__.py, relative imports) are seen as unintuitive by some, but defended as consistent with Python’s module model.