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
![python 2d list aliasing trap command prompt Command Prompt output showing that [[0]*cols]*rows makes every row change together while a list comprehension creates independent rows](https://pythonguides.com/wp-content/uploads/2026/09/python-2d-list-aliasing-trap-command-prompt.png)
* 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.