How Python Caches Small Integers Between -5 and 256

In Python, numbers are not primitive data types but fully allocated objects that consume memory and processing time during creation. To optimize performance and reduce memory usage, the standard Python implementation (CPython) pre-allocates and caches all integer objects between -5 and 256 during interpreter initialization. This article breaks down how this small integer caching mechanism works under the hood, why this specific range exists, and how it directly affects identity checks in your code.

The Underlying Mechanism in CPython

In CPython, every integer is an instance of PyLongObject. Allocating and deallocating memory each time a number is referenced would create significant overhead. To resolve this, CPython defines two internal macros:

During the interpreter's startup routine, CPython creates a static array containing pre-allocated integer objects covering the range from -NSMALLNEGINTS to NSMALLPOSINTS - 1, corresponding to the range [-5, 256].

Whenever an integer is created in your code—whether through assignment, a function return value, or an arithmetic operation—CPython checks if the resulting value falls within this inclusive range. If it does, Python does not allocate a new PyLongObject. Instead, it increments the reference count of the existing cached object in the array and returns a pointer to it.

Why the -5 to 256 Range Was Chosen

The range of -5 to 256 is an empirical design choice based on typical programming patterns:

Extending the cache to a much larger range would waste system memory by keeping unused objects permanently loaded, while a smaller range would lose the performance gains achieved by avoiding repeated memory allocation.

Identity (is) vs. Equality (==)

Because cached integers are singletons in memory, this mechanism directly influences the behavior of the identity operator (is), which checks whether two variables point to the exact same memory address.

# Within the cached range
a = 100
b = 100
print(a is b)   # True (both point to the same cached object)
print(a == b)   # True (values are equal)

# Outside the cached range (in the interactive REPL)
x = 300
y = 300
print(x is y)   # False (distinct objects allocated in memory)
print(x == y)   # True (values are equal)

Note: Running code from a script file or single compilation block may show x is y as True for numbers outside this range due to a separate optimization called code-block constant folding. However, the small integer cache is global, permanent, and independent of compiler optimizations.

Key Takeaways

  1. Automatic Initialization: CPython allocates an array of 262 integer objects (-5 to 256) at startup.
  2. Pointer Reuse: Any variable holding a value within this boundary references the pre-existing object rather than instantiating a new one.
  3. Always Use == for Values: Never rely on is to compare numerical values, as relying on object identity will fail as soon as an integer exceeds the boundaries of the cache.