Understanding None as a Singleton in Python
In Python, None is the standard constant used to signal
the absence of a value or an empty state, implemented strictly as a
singleton instance of the NoneType class. This article
examines how Python internally defines None within the
CPython runtime, why only a single instance exists across the
interpreter's lifecycle, the technical distinction between identity and
equality checks, and how the interpreter enforces its immutability.
The Singleton Nature of
None
A singleton is a design pattern that restricts the instantiation of a
class to a single object. In Python, None is an absolute
singleton: there is only one None object created when the
Python interpreter starts, and it persists until the process
terminates.
Regardless of where, when, or how many times you assign
None to a variable, every variable points to the exact same
location in memory.
a = None
b = None
print(a is b) # True
print(id(a) == id(b)) # TrueBecause None is a singleton, checking for it requires
checking object identity rather than value equality.
Implementation in CPython
Under the hood in CPython (the reference implementation of Python
written in C), None is defined as a static object.
- The C Struct: In the CPython source code
(
object.handobject.c),Noneis defined as aPyObjectstructure named_Py_NoneStruct. - The Macro: The C API provides a global macro,
Py_None, which points directly to the address of_Py_NoneStruct:#define Py_None (&_Py_NoneStruct) - Reference Handling: Whenever a Python function does
not explicitly return a value, the interpreter returns
Py_None. In earlier versions of Python, every reference toNoneincremented its reference count viaPy_INCREF(Py_None). Starting in Python 3.12,Nonewas converted into an "immortal object," meaning its reference count remains effectively constant, avoiding memory bus contention across multi-threaded applications.
Preventing Re-instantiation
Python enforces the singleton pattern by preventing user-level
creation of NoneType instances. The class of
None is NoneType, accessible via
type(None).
If you attempt to call NoneType() directly to create a
new instance, Python raises a TypeError:
NoneType = type(None)
new_instance = NoneType()
# TypeError: cannot create 'NoneType' instancesFurthermore, None is a reserved keyword in Python. You
cannot reassign it, shadow it in local scopes, or bind a new value to
the identifier:
None = 5
# SyntaxError: cannot assign to NoneIdentity (is) vs.
Equality (==)
Because None is guaranteed to be a singleton, the
recommended and idiomatic way to test whether a value is
None is the is operator, not
==.
val is None: Checks pointer equality. It evaluates whether the memory address ofvalis identical to the address of_Py_NoneStruct. This is an extremely fast, \(O(1)\) CPU instruction that cannot be overridden by user classes.val == None: Invokes the__eq__()method on the object bound toval. This carries performance overhead and introduces potential bugs if a custom class implements__eq__()to returnTruewhen evaluated againstNone.
class FaultyComparison:
def __eq__(self, other):
return True
obj = FaultyComparison()
print(obj == None) # True (Misleading)
print(obj is None) # False (Accurate)Using is guarantees that the comparison checks for the
actual, unique singleton object defined by the interpreter.