A 2D array in Python is a table of values arranged in rows and columns. Python has no built-in 2D array type, so you use either a nested list (a list of rows, like [[1, 2], [3, 4]]) or a NumPy 2D array created with np.array(), np.zeros() and similar functions. Nested lists are fine for small, mixed data; NumPy is faster and gives you column slicing and maths on whole arrays. This guide shows how to create, access, modify and display both, including the [[0] * n] * m trap and reading a 2D array from user input.
All examples were run with Python 3.12.5, NumPy 2.5.3 and Matplotlib 3.11.2 in the Windows Command Prompt; the chart is a real Matplotlib window. Reference: NumPy: the absolute basics for beginners and nested list comprehensions.
Nested list vs NumPy 2D array
import numpy as np
# 1. a nested list: a list of rows
seats = [[1, 0, 1],
[0, 0, 1],
[1, 1, 1]]
print(seats[1][2]) # row 1, column 2
# 2. a NumPy 2D array
grid = np.array(seats)
print(grid[1, 2], grid.shape) # same cell, and (rows, columns)
Output:
1
1 (3, 3)
| Nested list | NumPy 2D array | |
|---|---|---|
| Create | [[1, 2], [3, 4]] | np.array([[1, 2], [3, 4]]) |
| One cell | a[1][0] | a[1, 0] |
| A column | [row[0] for row in a] | a[:, 0] |
| Rows can differ in length | Yes | No (rectangular) |
| Maths on all values | Loops | a * 2, a.sum(axis=0) |
| Speed / memory | Slower, more memory | Much faster, compact |
Create a 2D list correctly (the [[0] * n] * m trap)
Multiplying the outer list copies references to the same inner list, so changing one row changes all of them. Use a list comprehension to build a new list for every row:
rows, cols = 3, 4
wrong = [[0] * cols] * rows # the SAME inner list three times
wrong[0][0] = 9
print("wrong:", wrong)
right = [[0] * cols for _ in range(rows)] # a new inner list for every row
right[0][0] = 9
print("right:", right)
print("rows share one list?", wrong[0] is wrong[1], "/", right[0] is right[1])
Output:
wrong: [[9, 0, 0, 0], [9, 0, 0, 0], [9, 0, 0, 0]]
right: [[9, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
rows share one list? True / False
* rows, all rows are the same list object.Create a 2D array with NumPy
NumPy has a function for every common starting point:
import numpy as np
print(np.zeros((2, 3))) # all zeros
print(np.ones((2, 3), dtype=int)) # all ones, integers
print(np.full((2, 3), 7)) # any value
print(np.arange(1, 13).reshape(3, 4)) # 1..12 as 3 rows x 4 columns
print(np.eye(3, dtype=int)) # identity matrix
rng = np.random.default_rng(0)
print(rng.integers(1, 100, size=(2, 4))) # random integers
Output:
[[0. 0. 0.]
[0. 0. 0.]]
[[1 1 1]
[1 1 1]]
[[7 7 7]
[7 7 7]]
[[ 1 2 3 4]
[ 5 6 7 8]
[ 9 10 11 12]]
[[1 0 0]
[0 1 0]
[0 0 1]]
[[85 64 51 27]
[31 5 8 2]]
| Function | Result |
|---|---|
np.zeros((r, c)) | All zeros (float by default) |
np.ones((r, c)) | All ones |
np.full((r, c), value) | Every cell set to a value |
np.arange(n).reshape(r, c) | A sequence arranged in rows |
np.eye(n) | Identity matrix |
rng.integers(lo, hi, size=(r, c)) | Random integers |
Access rows, columns and cells
NumPy uses one pair of brackets with a comma: arr[row, col]. Slices work on both axes, and axis=0 / axis=1 tell functions whether to work down the columns or across the rows:
import numpy as np
sales = np.array([[120, 135, 150], # store A: Jan, Feb, Mar
[ 90, 110, 105], # store B
[200, 180, 210]]) # store C
print("store B, Feb:", sales[1, 1])
print("row of store C:", sales[2])
print("all March values:", sales[:, 2]) # a column
print("first two stores, last two months:\n", sales[:2, 1:])
print("total per store:", sales.sum(axis=1))
print("total per month:", sales.sum(axis=0))
nested = sales.tolist() # back to a nested list
print("column from a nested list:", [row[2] for row in nested])
Output:
store B, Feb: 110
row of store C: [200 180 210]
all March values: [150 105 210]
first two stores, last two months:
[[135 150]
[110 105]]
total per store: [405 305 590]
total per month: [410 425 465]
column from a nested list: [150, 105, 210]
Add rows and columns and update values
import numpy as np
matrix = [[1, 2], [3, 4]]
matrix.append([5, 6]) # add a row to a nested list
for row in matrix:
row.append(0) # add a column
print(matrix)
arr = np.array([[1, 2], [3, 4]])
arr = np.vstack([arr, [5, 6]]) # add a row (returns a new array)
arr = np.hstack([arr, np.zeros((3, 1), dtype=int)]) # add a column
arr[0, 0] = 99 # update one cell
print(arr)
print("transposed:\n", arr.T)
Output:
[[1, 2, 0], [3, 4, 0], [5, 6, 0]]
[[99 2 0]
[ 3 4 0]
[ 5 6 0]]
transposed:
[[99 3 5]
[ 2 4 6]
[ 0 0 0]]
Lists change in place with append(). NumPy arrays have a fixed size, so np.vstack(), np.hstack() and np.append() return a new array; when you add many rows, collect them in a list first and convert once at the end.
Create a 2D array from user input
rows = int(input("Rows: "))
cols = int(input("Columns: "))
matrix = []
for r in range(rows):
values = input(f"Row {r + 1} ({cols} numbers separated by spaces): ").split()
matrix.append([int(v) for v in values[:cols]])
print("Your 2D array:")
for row in matrix:
print(row)
Output (the user typed 2, 3 and two rows of numbers):
Rows: 2
Columns: 3
Row 1 (3 numbers separated by spaces): 4 5 6
Row 2 (3 numbers separated by spaces): 7 8 9
Your 2D array:
[4, 5, 6]
[7, 8, 9]
For a NumPy array, wrap the result: np.array(matrix).
Nested list vs NumPy: speed
import time
import numpy as np
n = 1000
nested = [[i * n + j for j in range(n)] for i in range(n)]
arr = np.array(nested)
start = time.perf_counter()
total = sum(sum(row) for row in nested)
t_list = time.perf_counter() - start
start = time.perf_counter()
total_np = arr.sum()
t_np = time.perf_counter() - start
print(f"nested list sum: {total} in {t_list * 1000:.1f} ms")
print(f"NumPy array sum: {total_np} in {t_np * 1000:.1f} ms")
print(f"memory: list of lists ~{sum(map(len, nested)) * 28 // 1_000_000} MB of int objects, NumPy {arr.nbytes // 1_000_000} MB")
Output (one run; timings differ between computers):
nested list sum: 499999500000 in 4.7 ms
NumPy array sum: 499999500000 in 0.7 ms
memory: list of lists ~28 MB of int objects, NumPy 8 MB
Display a 2D array as a grid
imshow() draws each cell as a coloured square, which makes patterns in a 2D array easy to see:
import matplotlib.pyplot as plt
import numpy as np
sales = np.array([[120, 135, 150, 170],
[ 90, 110, 105, 125],
[200, 180, 210, 240]])
fig, ax = plt.subplots(figsize=(6, 3.8))
im = ax.imshow(sales, cmap="YlGn") # show the 2D array as a grid
ax.set_xticks(range(4), ["Jan", "Feb", "Mar", "Apr"])
ax.set_yticks(range(3), ["Store A", "Store B", "Store C"])
for (r, c), value in np.ndenumerate(sales):
ax.text(c, r, value, ha="center", va="center", color="white" if value > 190 else "black")
fig.colorbar(im, ax=ax, label="Sales")
plt.tight_layout()
plt.show()
imshow().Save and load a 2D array
import numpy as np
arr = np.arange(12).reshape(3, 4)
np.savetxt("grid.csv", arr, delimiter=",", fmt="%d") # readable text file
loaded = np.loadtxt("grid.csv", delimiter=",", dtype=int)
np.save("grid.npy", arr) # fast binary file
print(np.array_equal(arr, np.load("grid.npy")))
Related Python array and NumPy tutorials:
- Check if a NumPy array is empty
- Initialize a 2D array in Python
- Iterate through a 2D array in Python
- Find the maximum value in an array
Frequently asked questions
How do I create a 2D array in Python?
Use a nested list, [[0] * cols for _ in range(rows)], or NumPy, np.zeros((rows, cols)).
Does Python have a built-in 2D array?
No. The standard approaches are a list of lists or a NumPy ndarray with two dimensions.
Why does [[0] * cols] * rows give wrong results?
It repeats a reference to the same inner list, so all rows change together. Build each row separately with a list comprehension.
How do I get a column from a 2D array?
NumPy: arr[:, col]. Nested list: [row[col] for row in matrix].
How do I find the number of rows and columns?
NumPy: rows, cols = arr.shape. Nested list: len(matrix) and len(matrix[0]).
Should I use a nested list or NumPy?
Use NumPy for numbers and anything larger than a small table; use nested lists for small grids or mixed data types.
Bijay Kumar is a 13-time Microsoft MVP with more than 18 years in software development, and the founder of Python Guides and TSinfo Technologies. He started out building .NET and SharePoint solutions at HP, TCS and KPIT before moving into Python, machine learning and AI, and he also builds web apps with TypeScript and React. He writes the tutorials here himself, and every example is run before publishing so you see the real output. More about Bijay · Microsoft MVP profile · LinkedIn