The numpy.empty() function allocates an uninitialized array of a given shape and dtype without zero-filling entries.
Maximum Allocation Speed: By skipping memory zero-filling, np.empty() delivers the fastest array creation in NumPy for pre-allocating output buffers. To clone dimensions from an existing array, use numpy.empty_like(), or see numpy.full().
The signature for numpy.empty() is defined as:
# Formal syntax of numpy.empty()
numpy.empty(shape, dtype=float, order='C', *, like=None)
| Parameter | Type | Default | Description & Operational Rule |
|---|---|---|---|
shape |
int or tuple |
Required | Shape of the empty array (e.g. 5, (3, 4)). |
dtype |
data-type |
float64 |
Data type of array elements (e.g. np.int32, np.float32). |
order |
{'C', 'F'} |
'C' |
Memory layout: 'C' (row-major) or 'F' (column-major order). |
like |
array_like |
None |
Reference object for array creation (NumPy 1.20+). |
| Return | ndarray |
N/A | Uninitialized array of given shape, dtype, and memory order. |
| Time Complexity | O(1) | N/A | Constant-time allocation since byte zeroing is skipped. |
Create uninitialized arrays across any dimension by passing an integer or tuple:
# 1. Uninitialized arrays across dimensions
import numpy as np
# 1D vector (4 elements)
vec_1d = np.empty(4)
print("1D Vector:", vec_1d.shape, vec_1d.dtype)
# 2D matrix (3 rows, 4 columns)
mat_2d = np.empty((3, 4))
print("2D Matrix shape:", mat_2d.shape)
# 3D tensor (2 batches, 2 rows, 3 columns)
tensor_3d = np.empty((2, 2, 3), dtype=np.int32)
print("3D Tensor shape:", tensor_3d.shape)Terminal Output:
1D Vector: (4,) float64
2D Matrix shape: (3, 4)
3D Tensor shape: (2, 2, 3)
np.zeros() zeroes every byte in memory, while np.empty() skips zeroing for speed:
# 2. Performance benchmark: empty() vs. zeros()
import numpy as np
import time
shape = (5000, 5000) # 25M elements (~200 MB)
# np.empty() skips memory zeroing
t0 = time.perf_counter()
arr_empty = np.empty(shape, dtype=np.float64)
t_empty = time.perf_counter() - t0
# np.zeros() zero-fills memory
t0 = time.perf_counter()
arr_zeros = np.zeros(shape, dtype=np.float64)
t_zeros = time.perf_counter() - t0
print(f"np.empty(): {t_empty * 1000:.3f} ms (fastest)")
print(f"np.zeros(): {t_zeros * 1000:.3f} ms")Terminal Output:
np.empty(): 0.018 ms (fastest)
np.zeros(): 12.450 ms
Explicitly specifying data types like uint8 or float32 optimizes RAM bandwidth:
# 3. Precision control: custom data types
import numpy as np
# 8-bit unsigned integer for pixel channels (0-255)
img_buf = np.empty((2, 2), dtype=np.uint8)
print("uint8 itemsize: ", img_buf.itemsize, "byte")
# 32-bit float for neural network weights
weights = np.empty((3, 3), dtype=np.float32)
print("float32 itemsize:", weights.itemsize, "bytes")
# Fixed-width unicode strings (up to 10 characters)
str_buf = np.empty(3, dtype='U10')
str_buf[:] = ["Alpha", "Beta", "Gamma"]
print("String buffer: ", str_buf)Terminal Output:
uint8 itemsize: 1 byte
float32 itemsize: 4 bytes
String buffer: ['Alpha' 'Beta' 'Gamma']
Row-major ('C') stores rows contiguously; Column-major ('F') stores columns contiguously:
# 4. Memory layout order: C-style vs. Fortran-style
import numpy as np
# Row-major order ('C' - default in C/Python)
arr_c = np.empty((3, 3), order='C')
print("C-contiguous:", arr_c.flags['C_CONTIGUOUS'])
print("C strides: ", arr_c.strides)
# Column-major order ('F' - Fortran/MATLAB style)
arr_f = np.empty((3, 3), order='F')
print("F-contiguous:", arr_f.flags['F_CONTIGUOUS'])
print("F strides: ", arr_f.strides)Terminal Output:
C-contiguous: True
C strides: (24, 8)
F-contiguous: True
F strides: (8, 24)
To mirror an existing array's shape and precision, numpy.empty_like() clones geometry automatically:
# 5. Mirroring geometries with numpy.empty_like()
import numpy as np
prototype = np.array([[10.5, 20.3], [40.7, 50.9]], dtype=np.float32)
# Allocate scratchpad matching prototype's shape & dtype
scratch = np.empty_like(prototype)
print("Prototype:", prototype.shape, prototype.dtype)
print("Scratch: ", scratch.shape, scratch.dtype)Terminal Output:
Prototype: (2, 2) float32
Scratch: (2, 2) float32
| Constructor | Initial Content | Speed | Memory Safe? | Primary Use Case |
|---|---|---|---|---|
np.empty() |
Uninitialized | Fastest (O(1)) | No | Pre-allocated scratchpads and buffers. |
np.zeros() |
Zeros (0.0) |
Moderate (O(N)) | Yes | Counters, masks, and default states. |
np.ones() |
Ones (1.0) |
Moderate (O(N)) | Yes | Multiplicative baselines, unit weights. |
np.full() |
Constant | Moderate (O(N)) | Yes | Sentinel values (NaN, -1, Inf). |
Recipe A: Pre-Allocated Loop Accumulator. Pre-allocating with np.empty() avoids repeated np.append() memory reallocation:
# 6. Production Recipe: Pre-allocated loop accumulator
import numpy as np
n = 5
results = np.empty(n, dtype=np.float64)
for i in range(n):
results[i] = (i + 1) ** 2.5
print("Populated buffer:", results)Terminal Output:
Populated buffer: [ 1. 5.65685425 15.58845727 32. 55.90169944]Recipe B: Frame Buffer. Pre-allocating an uninitialized frame buffer eliminates memory overhead during video capture:
# 7. Production Recipe: Streaming video frame buffer
import numpy as np
h, w = 480, 640
frame = np.empty((h, w, 3), dtype=np.uint8)
frame[:, :, 0] = 255 # Red
frame[:, :, 1] = 128 # Green
frame[:, :, 2] = 0 # Blue
print("Frame shape:", frame.shape)
print("Total bytes:", frame.nbytes, "bytes")Terminal Output:
Frame shape: (480, 640, 3)
Total bytes: 921600 bytes
Reading uninitialized memory produces unpredictable results, and str without a length truncates text:
# 8. Common traps: reading uninitialized memory
import numpy as np
# TRAP 1: Assuming empty() contains zeros or NaNs
raw = np.empty((2, 2)) # Values are whatever was in RAM previously!
# TRAP 2: Using str without length specification
str_trap = np.empty(3, dtype=str)
str_trap[0] = "Supercalifragilistic"
print("Truncated string:", str_trap[0]) # Truncates to 1 char!Terminal Output:
Truncated string: S
Practice array creation and buffer allocations in our companion Jupyter Notebook hosted in the plus2net/numpy repository:
Benchmark allocation speeds against np.zeros() and run self-validating unit assertions.
Run these unit checks directly in Python or your local environment to verify np.empty() mechanics:
# 9. Self-verifying unit test suite for numpy.empty()
import numpy as np
# Test 1: Shape and dimension verification
a1 = np.empty((3, 5))
assert a1.shape == (3, 5) and a1.ndim == 2
# Test 2: Custom dtype verification
a2 = np.empty((4,), dtype=np.int32)
assert a2.dtype == np.int32 and a2.itemsize == 4
# Test 3: empty_like geometry matching
proto = np.zeros((2, 3, 4), dtype=np.float32)
a3 = np.empty_like(proto)
assert a3.shape == (2, 3, 4) and a3.dtype == np.float32
# Test 4: Overwriting guarantees valid data
buf = np.empty(3)
buf[:] = [10.0, 20.0, 30.0]
assert np.allclose(buf, [10.0, 20.0, 30.0])
print("All numpy.empty() unit assertions successfully verified!")Terminal Output:
All numpy.empty() unit assertions successfully verified!
Operating systems zero-fill new pages for security. Never rely on this; dirty pages return garbage.
Use np.empty() when pre-allocating an output buffer that will be completely overwritten before reading. Otherwise use np.zeros().
np.empty(shape) takes explicit dimensions. np.empty_like(prototype) copies shape and dtype from an existing array.
Virtual address space is reserved immediately, but physical RAM pages are committed only when elements are first written.
Author & Instructor at plus2net
I write and maintain practical tutorials on Python, PHP, SQL, JavaScript, HTML, jQuery, and web development at plus2net. The tutorials focus on clear explanations, working examples, and code that readers can test and adapt while learning.