Using Python Built In Constants
Python# Correct usage patterns for Python built-in constants # None: absence of a value, always compare with `is` def find_user(id): result = None return result if result is None: print("not found") # True/False: instances of bool, subclass of int assert True == 1 and False == 0 assert isinstance(True, int) # NotImplemented: returned from special methods, not raised class Vector: def __eq__(self, other): if not isinstance(other, Vector): return NotImplemented return self.x == other.x # Ellipsis (...): placeholder in slicing, stubs, type hints def stub_function() -> int: ... matrix[..., 0] # slice shorthand for multi-dim arrays # __debug__: True unless run with -O flag if __debug__: print("debug mode checks run") assert some_condition # skipped entirely when -O is used # Site-module constants (interactive shell only, not for scripts) # quit, exit, copyright, credits, license
Progress:
- Identify which constant fits the semantic need (null vs boolean vs unimplemented vs placeholder)
- Use correct comparison idiom (
is/is notfor None, NotImplemented) - Never use site-module constants (
quit,exit,copyright, etc.) in production code - Use
__debug__for development-only assertions, not for security or business logic - Return
NotImplemented(don't raise it) inside dunder methods when operation isn't supported
Step 1: Distinguish the six core constants
| Constant | Type | Purpose | Comparison |
|---|---|---|---|
True/False | bool | Boolean truth values | ==, is both work (singletons) |
None | NoneType | "No value" / null | Always is None / is not None |
NotImplemented | NotImplementedType | Signal unsupported operation in rich comparisons/arithmetic dunders | Return it, don't raise; don't use in boolean context |
Ellipsis (...) | EllipsisType | Placeholder — slicing, stub bodies, type hints | Rarely compared; used as syntax ... |
__debug__ | bool | True normally, False with -O/-OO | Use in if __debug__: guards |
Step 2: Apply idiomatic patterns
None checks:
Pythonif value is None: # correct if value == None: # avoid — triggers __eq__, can misbehave
NotImplemented in operator overloading:
Pythondef __lt__(self, other): if not isinstance(other, MyClass): return NotImplemented # let Python try other.__gt__ or raise TypeError return self.value < other.value
Never do if x == NotImplemented or use it as a boolean — treat it strictly as a return sentinel.
Ellipsis for stubs and slicing:
Pythondef not_yet_implemented(): ... # numpy-style slicing arr[..., 0] # equivalent to arr[:, :, 0] for 3D array
debug for assert-guarded code:
Pythonif __debug__: _validate_invariants() # stripped out entirely under python -O
Never rely on __debug__/assert for security checks — they vanish under -O.
Step 3: Handle site-module constants correctly
quit, exit, copyright, credits, license are added by the site module only in interactive interpreter sessions. They:
- Are NOT guaranteed to exist in scripts, embedded interpreters, or when run with
-S - Should never be used programmatically (e.g.,
exit()in a script) — usesys.exit()instead - Exist purely for human convenience at the REPL
Python# Bad: script relying on interactive-only builtins exit() # may not exist if site module wasn't imported # Good: import sys sys.exit(0)
Example 1:
Input: Function should return None when no match is found, and caller needs to check.
Output:
Pythondef find(items, target): for item in items: if item == target: return item return None result = find([1, 2, 3], 5) if result is None: print("Not found")
Example 2:
Input: Implement __eq__ for a custom class that should support comparison only with same type.
Output:
Pythonclass Point: def __init__(self, x, y): self.x, self.y = x, y def __eq__(self, other): if not isinstance(other, Point): return NotImplemented return self.x == other.x and self.y == other.y
Example 3:
Input: Write a type stub file (.pyi) function signature with no body.
Output:
Pythondef process(data: list[int]) -> dict[str, int]: ...
Example 4:
Input: Code has assert isinstance(x, int) used to validate untrusted user input for a security check.
Output: Flag as pitfall — replace with explicit runtime check:
Pythonif not isinstance(x, int): raise TypeError("x must be int")
Reason: assert and reliance on __debug__ are removed with -O, so security-critical validation must never depend on them.
- Always use
is/is notforNoneandNotImplemented— they are singletons; identity comparison is faster and avoids operator overload surprises. - Return
NotImplemented, never raise it — raising breaks Python's reflected-operation fallback mechanism (__radd__,__req__, etc.). - Use
Ellipsis/...for stub bodies instead ofpasswhen signaling "unimplemented but intentional" (helps distinguish from placeholderpass). - Gate expensive diagnostic code with
if __debug__:to let-Ooptimize it away in production. - Prefer
sys.exit()over the site-addedexit()/quit()in any script or module. - Remember
boolis a subclass ofint:True + True == 2is valid but should be avoided for readability — don't rely on this arithmetic behavior in serious code.
- Comparing with
==instead ofisforNone/NotImplemented— can trigger unexpected__eq__behavior or return ambiguous truthy/falsy results. - Using
NotImplementedin a boolean context (e.g.,if not_implemented_value:) — it's truthy, soif x:doesn't tell you whether an operation failed; always checkis NotImplementedexplicitly if needed. - Confusing
NotImplementedwithNotImplementedError— the former is a value returned from dunder methods; the latter is an exception raised in abstract methods. They are not interchangeable. - Relying on
assert/__debug__for input validation or security — stripped underpython -O, creating silent security holes. - Using
quit(),exit(),copyright,credits,licensein production scripts — only guaranteed in interactive sessions; absent whensiteisn't imported (e.g.,-Sflag, embedded interpreters, some frozen apps). - Overusing
Ellipsisoutside stubs/slicing — using...as a generic "TODO" placeholder in real logic paths can silently pass type checks while doing nothing at runtime.