Data types (dtypes) & memory
Every NumPy array has a single dtype that decides how each element is stored in memory. Picking the right one can shrink a dataset several times over, and picking the wrong one can silently give wrong answers.
Common dtypes
| dtype | Bytes per value | Range / precision | Typical use |
|---|---|---|---|
int8 |
1 | -128 to 127 | Small codes, ratings 1–5 |
int32 |
4 | about ±2.1 billion | Counts, IDs |
int64 |
8 | about ±9.2 x 10^18 | Default integer on most platforms |
float32 |
4 | ~7 significant digits | ML features, images |
float64 |
8 | ~15–16 significant digits | Default float, finance, science |
bool |
1 | True / False | Masks |
Inspecting and converting
import numpy as np
qty = np.array([3, 5, 2, 8])
print(qty.dtype, qty.itemsize, qty.nbytes) # int64 8 32
qty_small = qty.astype(np.int16)
print(qty_small.nbytes) # 8
prices = np.array([199.0, 249.5, 99.9], dtype=np.float32)
print(np.iinfo(np.int16).max) # 32767
print(np.finfo(np.float32).eps) # machine precision of float32
astype always returns a new array, so assign the result back.
Memory at scale
One crore (10 million) sensor readings:
n = 10_000_000
print(np.zeros(n, dtype=np.float64).nbytes / 1e6) # 80.0 MB
print(np.zeros(n, dtype=np.float32).nbytes / 1e6) # 40.0 MB
print(np.zeros(n, dtype=np.int8).nbytes / 1e6) # 10.0 MB
For store IDs between 0 and 500, int16 is plenty. For temperatures to one decimal place, float32 is enough.
Trap 1: integer overflow wraps silently
Array arithmetic does not check for overflow. It simply wraps around:
stock = np.array([100, 120], dtype=np.int8)
print(stock + stock) # [-56 -16] -- wrong, no error raised!
Always check np.iinfo(dtype) limits before downcasting, especially for sums and products, which grow fast.
Trap 2: floating-point precision
Binary floats cannot represent most decimals exactly:
print(0.1 + 0.2 == 0.3) # False
print(np.isclose(0.1 + 0.2, 0.3)) # True
Compare floats with np.isclose or np.allclose, never ==. For money, many teams store paise as integers
(₹249.50 becomes 24950) to avoid rounding drift in totals.
Trap 3: upcasting in mixed operations
Combining dtypes promotes to a type that can hold both, so an int8 array plus a float64 array gives float64.
Your carefully small array can quietly become large again.
Strings and objects
np.array(["Pune", "Delhi"]) creates a fixed-width Unicode dtype such as <U5, sized to the longest string.
Mixed Python objects give dtype=object, which loses NumPy's speed because every element is a Python object.
For text-heavy data, pandas is usually the better tool.
Key takeaways
- Check
dtype,itemsizeandnbyteswhen memory matters. - Downcast only after checking value ranges with
np.iinfo/np.finfo. - Integer overflow in arrays is silent; floats are approximate.
- Avoid
objectarrays for numerical work.
Practice
Create an array of 1,000,000 random exam marks between 0 and 100. Store it as int64, then as the smallest
safe integer dtype, and print the memory saved. Then show what goes wrong if you sum the marks in int16
versus int64.