NumPy zeros(): Create Arrays of Zeros with np.zeros

np.zeros() creates a NumPy array of a given shape filled with zeros. Pass one number for a 1D array or a tuple for more dimensions, and add dtype if you don’t want floats:

import numpy as np

np.zeros(5)                  # [0. 0. 0. 0. 0.]
np.zeros((3, 2))             # 3 rows, 2 columns
np.zeros(4, dtype=int)       # [0 0 0 0]

Below I cover the shape rules, dtypes, zeros_like(), how it compares with np.empty(), and the errors people hit. Everything ran on Python 3.14.7 and NumPy 2.5.3.

Matplotlib window showing an image with red and blue blocks drawn on a NumPy zeros uint8 array
Every pixel starts at zero, which is black, and slicing paints the blocks on top.

NumPy zeros() syntax and parameters

The full signature is np.zeros(shape, dtype=float, order='C', *, like=None). In practice you’ll set the first two:

  • shape: an int like 5, or a tuple like (3, 2) for rows and columns.
  • dtype: the element type. It defaults to float64, so zeros print as 0..
  • order: 'C' stores rows together, 'F' stores columns together. It only matters for speed with some libraries.
  • like: lets array libraries that follow NumPy’s protocol return their own array type. You can ignore it for plain NumPy.

If import numpy fails, install it first with pip install numpy. The NumPy not found guide covers the usual install problems.

Create a 1D array of zeros with np.zeros

A single integer gives a one-dimensional array of that length:

import numpy as np

a = np.zeros(5)

print(a)
print("dtype:", a.dtype, "| shape:", a.shape, "| ndim:", a.ndim)
print(repr(a))

Output:

[0. 0. 0. 0. 0.]
dtype: float64 | shape: (5,) | ndim: 1
array([0., 0., 0., 0., 0.])

The dots in 0. mean these are floats, and dtype confirms float64. The shape (5,) is a one-item tuple, which is how NumPy writes a 1D shape.

Create a 2D or 3D array of zeros

For more than one dimension, pass the shape as a tuple. This also answers a common quiz question: the shape of np.zeros((3, 2)) is (3, 2).

import numpy as np

m = np.zeros((3, 2))
print(m)
print("shape:", m.shape)
print()

cube = np.zeros((2, 3, 4))
print("cube shape:", cube.shape, "| size:", cube.size)
print("np.zeros((3, 0)).shape:", np.zeros((3, 0)).shape)
print()

try:
    np.zeros(3, 2)
except TypeError as err:
    print("np.zeros(3, 2) -> TypeError:", err)

Output:

[[0. 0.]
 [0. 0.]
 [0. 0.]]
shape: (3, 2)

cube shape: (2, 3, 4) | size: 24
np.zeros((3, 0)).shape: (3, 0)

np.zeros(3, 2) -> TypeError: Cannot interpret '2' as a data type
Command Prompt showing NumPy zeros creating a 3 by 2 matrix and a 3D array and the TypeError from np.zeros(3, 2)
The tuple sets the shape, and forgetting the parentheses turns 2 into a dtype.

The first number is rows and the second is columns, so (3, 2) printed three rows of two. A 3D shape like (2, 3, 4) is two blocks of 3 by 4.

np.zeros(3, 2) fails because the second positional argument is dtype, and NumPy can’t use 2 as a type. Always wrap a multi-dimensional shape in its own parentheses.

For working with rows and columns once you have them, see 2D arrays in Python and the NumPy shape guide.

Set the dtype of a NumPy zeros array

dtype changes what the zeros are, and how much memory they take:

import numpy as np

kinds = {"default": None, "int": int, "np.float32": np.float32,
         "np.uint8": np.uint8, "bool": bool, "complex": complex}

for label, dt in kinds.items():
    z = np.zeros(3, dtype=dt)
    print(f"{label:<11} {str(z):<24} {str(z.dtype):<11} {z.nbytes:>2} bytes")

Output:

default     [0. 0. 0.]               float64     24 bytes
int         [0 0 0]                  int64       24 bytes
np.float32  [0. 0. 0.]               float32     12 bytes
np.uint8    [0 0 0]                  uint8        3 bytes
bool        [False False False]      bool         3 bytes
complex     [0.+0.j 0.+0.j 0.+0.j]   complex128  48 bytes
Command Prompt showing NumPy zeros with int float32 uint8 bool and complex dtypes and their size in bytes
The same three zeros take 3 to 48 bytes depending on the dtype.

dtype=int gave int64 on this Windows machine. NumPy 1.x used 32-bit integers on Windows, and NumPy 2 changed that, so older tutorials may show int32.

Zeros of type bool are False. float32 and uint8 save memory for large arrays, such as images or machine learning inputs.

Small types have a catch. uint8 holds 0 to 255, and arithmetic wraps around silently:

import numpy as np

pixels = np.zeros(3, dtype=np.uint8)
pixels[0] = 250
pixels += 10
print("250 + 10 in uint8:", pixels)

try:
    pixels += 300
except OverflowError as err:
    print("OverflowError:", err)

Output:

250 + 10 in uint8: [ 4 10 10]
OverflowError: Python integer 300 out of bounds for uint8

250 plus 10 became 4 with no warning. Adding the plain Python number 300 at least raised OverflowError, because it can’t fit at all. NumPy data types lists every type and its range.

np.zeros_like(): zeros with another array’s shape

np.zeros_like(a) makes a zero array with the same shape and dtype as a. The dtype part is easy to miss:

import numpy as np

prices = np.array([19, 24, 31])          # integers
discounts = np.zeros_like(prices)
discounts[0] = 2.5
print("zeros_like(prices):", discounts, discounts.dtype)

discounts = np.zeros_like(prices, dtype=float)
discounts[0] = 2.5
print("with dtype=float:  ", discounts, discounts.dtype)
print()

grid = np.array([[1.5, 2.0], [3.1, 4.8]])
print(np.zeros_like(grid))
print("same as np.zeros(grid.shape, dtype=grid.dtype):",
      np.array_equal(np.zeros_like(grid), np.zeros(grid.shape, dtype=grid.dtype)))

Output:

zeros_like(prices): [2 0 0] int64
with dtype=float:   [2.5 0.  0. ] float64

[[0. 0.]
 [0. 0.]]
same as np.zeros(grid.shape, dtype=grid.dtype): True
Command Prompt showing NumPy zeros_like keeping an integer dtype so 2.5 is stored as 2
zeros_like() copies the dtype too, so an integer template truncates 2.5 to 2.

prices held integers, so discounts did too, and 2.5 was stored as 2 without any error. Passing dtype=float fixes it.

For a float template, np.zeros_like(grid) is simply a shorter way to write np.zeros(grid.shape, dtype=grid.dtype), and the last line confirms they match.

Check if an array is all zeros

The reverse question comes up too: is everything in this array still zero? You don’t need to compare each value yourself:

import numpy as np

a = np.zeros((2, 3))
b = a.copy()
b[1, 2] = 0.001

print("a is all zeros:", not a.any())
print("b is all zeros:", not b.any())
print("nonzero values in b:", np.count_nonzero(b))

Output:

a is all zeros: True
b is all zeros: False
nonzero values in b: 1

a.any() is True if any element is nonzero, so not a.any() means all zeros. np.count_nonzero() tells you how many values changed, which caught the single 0.001 in b.

What is the difference between np.zeros and np.empty?

NumPy has a family of these functions. They all take the same shape and dtype arguments and differ only in the starting values:

import numpy as np

print("np.zeros: ", np.zeros(4))
print("np.ones:  ", np.ones(4))
print("np.full:  ", np.full(4, 7.5))
print("np.empty: ", np.empty(4).shape, "(values are whatever was in memory)")

Output:

np.zeros:  [0. 0. 0. 0.]
np.ones:   [1. 1. 1. 1.]
np.full:   [7.5 7.5 7.5 7.5]
np.empty:  (4,) (values are whatever was in memory)

np.ones() fills with 1, and np.full() fills with any value you give it. np.empty() doesn’t fill at all, so its values are whatever was already in that memory.

People reach for np.empty() to save time. Here’s what the timings looked like for ten million values:

import timeit
import numpy as np

n = 10_000_000

def ms(fn, number):
    return min(timeit.repeat(fn, number=number, repeat=3)) / number * 1e3

print(f"np.zeros(n):     {ms(lambda: np.zeros(n), 20):8.3f} ms")
print(f"np.empty(n):     {ms(lambda: np.empty(n), 20):8.3f} ms")
print(f"np.zeros(n) + 1: {ms(lambda: np.zeros(n) + 1, 5):8.3f} ms")
print(f"[0] * n:         {ms(lambda: [0] * n, 5):8.3f} ms")

Output:

np.zeros(n):        0.034 ms
np.empty(n):        0.030 ms
np.zeros(n) + 1:   36.610 ms
[0] * n:           26.127 ms

np.zeros() was as fast as np.empty(). NumPy asks the operating system for memory that’s already zeroed, and the real cost shows up on the first write, which is why adding 1 took far longer.

Building a plain list with [0] * n was in the same range as that first write. So use np.zeros() unless you’ll overwrite every value anyway. Creating an empty array in Python explains when np.empty() is the right choice.

np.zeros vs a Python list of zeros

Without NumPy, a list of zeros is [0] * n. It’s fine for one dimension, but the 2D version has a trap:

import numpy as np

row = [0] * 4
print(row, type(row).__name__)

grid = [[0] * 3] * 2
grid[0][0] = 9
print("shared rows:  ", grid)

grid = [[0] * 3 for _ in range(2)]
grid[0][0] = 9
print("separate rows:", grid)
print()

arr = np.zeros((2, 3), dtype=int)
arr[0, 0] = 9
print(arr)
print("back to a list:", arr.tolist())

Output:

[0, 0, 0, 0] list
shared rows:   [[9, 0, 0], [9, 0, 0]]
separate rows: [[9, 0, 0], [0, 0, 0]]

[[9 0 0]
 [0 0 0]]
back to a list: [[9, 0, 0], [0, 0, 0]]

[[0] * 3] * 2 repeats the same inner list twice, so changing one row changed both. A list comprehension builds separate rows, and np.zeros() never has this problem.

NumPy is worth it when you’ll do math on the numbers. For plain lists, creating an array of zeros in Python covers the list, array module and pandas options.

Common np.zeros errors and fixes

These are the errors that come up with np.zeros(), each caught so you can see the message:

import numpy as np

attempts = {
    "np.zeroes(3)": lambda: np.zeroes(3),
    "np.zeros(3, 2)": lambda: np.zeros(3, 2),
    "np.zeros(-1)": lambda: np.zeros(-1),
    "np.zeros(3.0)": lambda: np.zeros(3.0),
    "np.zeros('3')": lambda: np.zeros("3"),
}

for code, make in attempts.items():
    try:
        make()
    except (AttributeError, TypeError, ValueError) as err:
        print(f"{code:<15} {type(err).__name__}: {err}")

Output:

np.zeroes(3)    AttributeError: module 'numpy' has no attribute 'zeroes'
np.zeros(3, 2)  TypeError: Cannot interpret '2' as a data type
np.zeros(-1)    ValueError: negative dimensions are not allowed
np.zeros(3.0)   TypeError: expected a sequence of integers or a single integer, got '3.0'
np.zeros('3')   TypeError: 'str' object cannot be interpreted as an integer