Picking and checking dtypes avoids silent overflow, wasted memory and surprising type promotion.
The dtype says what each element is: int8...int64, unsigned uint8...uint64, float16/float32/float64, complex128, bool, plus fixed-width strings and object. NumPy infers it from your data ([1, 2] gives the platform default integer, which since NumPy 2 is int64 on all 64-bit systems including Windows; [1, 2.5] gives float64) or you pass dtype= explicitly.
a.astype(new_dtype) converts and always returns a new array. Converting floats to ints truncates toward zero; it does not round.
Fixed-size integers can overflow. Array arithmetic wraps around silently: an int8 holding 127 plus 1 becomes -128. NumPy 2 made Python scalars "weak" (NEP 50): in arr + 3 the array's dtype wins, so uint8_array + 1 stays uint8. And if the Python value cannot fit, as in uint8_array + 300, NumPy now raises OverflowError instead of quietly upcasting.
When two arrays meet, NumPy promotes to a type that can hold both: int64 + float64 gives float64, int8 + int16 gives int16. np.result_type(a, b) tells you what you'll get.
Memory is a dtype decision: a million float32 values take 4 MB, float64 takes 8 MB. Use smaller types when the precision is enough and memory or bandwidth matters (images in uint8, ML weights in float32).
Strings in classic NumPy are fixed-width (<U5 means Unicode, at most 5 characters), and longer values assigned later get truncated. NumPy 2 adds np.dtypes.StringDType() for variable-length strings.
Example
import numpy as np
a = np.array([1, 2, 3])
print(a.dtype) # int64
b = np.array([1, 2.5])
print(b.dtype) # float64
print(np.array([2.9, -2.9]).astype(int)) # [ 2 -2] truncates
small = np.array([127], dtype=np.int8)
print(small + np.int8(1)) # [-128] wrapped around!
pix = np.array([250, 10], dtype=np.uint8)
print((pix + 1).dtype) # uint8 (Python int is "weak")
print(pix.astype(np.int16) + 10) # [260 20] widen first
print(np.result_type(np.int8, np.float32)) # float32
print(np.array(["cat", "horse"]).dtype) # <U5Remember
- One dtype per array; check it with
a.dtype, change it withastype - Integer arithmetic wraps on overflow, silently
- In NumPy 2 the array's dtype wins over Python scalars (NEP 50)
- Smaller dtypes save memory but limit range and precision
Watch out for
- Assuming
astype(int)rounds: it truncates, so usenp.round(x).astype(int)if you mean rounding.