append, insert & delete
Add values at the end (np.append), at a position (np.insert) or remove them (np.delete) — why they always return new arrays and why calling them in a loop is slow.
Python lists have .append(), .insert() and del, and they change the list in place. NumPy has similar-looking functions — np.append, np.insert, np.delete — but they behave very differently: they never modify the original array, they always build a new one. Knowing this saves you from bugs and from painfully slow code.
Definition
np.append,np.insertandnp.deletereturn a new array with values added at the end, inserted before a given index, or removed at given indices. Because a NumPy array has a fixed size in one contiguous block of memory, every call allocates a new array and copies all the data.
- New array —
np.append(scores, 31)does not changescores; you must assign the result:scores = np.append(scores, 31). - Fixed size — a NumPy array cannot grow in place the way a list can (lists keep spare capacity; arrays don't).
- Copies all the data — adding one value to a 1-million-element array copies 1 million values. In a loop that becomes very slow.
- axis=None flattens — if you don't give
axis, all three functions flatten a 2D array to 1D first.
Syntax
python
np.append(arr, values, axis=None)
np.insert(arr, obj, values, axis=None)
np.delete(arr, obj, axis=None)| Parameter | Meaning | Default |
|---|---|---|
arr | the input array (not modified) | required |
values | values to add. With an axis, must have the right shape (same number of dimensions for append) | required |
obj | index / list of indices / slice (np.s_[::2]) where to insert or which to delete | required |
axis | axis to work along. None = flatten first | None |
Example — np.append
python
import numpy as np
scores = np.array([72, 45, 88])
new = np.append(scores, 31)
print(new)
print(scores)
print(np.append(scores, [64, 0, 103]))text
[72 45 88 31]
[72 45 88]
[ 72 45 88 64 0 103]How it works: new has 4 values, but scores is untouched — the original still has 3. Several values can be appended at once.
Example — np.append on 2D needs axis and matching dimensions
python
squad = np.array([[72, 45, 88],
[56, 0, 74]])
print(np.append(squad, [[45, 32, 0]], axis=0)) # new row
print(np.append(squad, [[31], [88]], axis=1)) # new column
print(np.append(squad, [45, 32, 0])) # no axis -> flattened!text
[[72 45 88]
[56 0 74]
[45 32 0]]
[[72 45 88 31]
[56 0 74 88]]
[72 45 88 56 0 74 45 32 0]How it works: with an axis, np.append is just np.concatenate, so values must be 2D ([[...]]). np.append(squad, [45, 32, 0], axis=0) with a 1D row fails with all the input arrays must have same number of dimensions. Without an axis, everything is flattened — usually not what you want.
Example — np.insert
python
print(np.insert(scores, 1, 100)) # 100 before index 1
print(np.insert(scores, [0, 2], [11, 22])) # several positions
print(np.insert(squad, 1, [99, 99, 99], axis=0)) # new row at index 1
print(np.insert(squad, 0, 0, axis=1)) # column of 0s at the fronttext
[ 72 100 45 88]
[11 72 45 22 88]
[[72 45 88]
[99 99 99]
[56 0 74]]
[[ 0 72 45 88]
[ 0 56 0 74]]How it works: obj is the index before which values go, measured in the original array. A scalar value (0) is broadcast to fill the whole new column. Unlike append, insert accepts a 1D row for a 2D array.
Note: values are converted to the array's dtype.
np.insert(np.array([1, 2, 3]), 1, 9.7)gives[1 9 2 3]— the 9.7 is truncated to the int 9.
Example — np.delete
python
season = np.array([72, 45, 88, 31, 64, 0, 103])
print(np.delete(season, 5)) # remove index 5
print(np.delete(season, [0, 2, 4])) # remove several
print(np.delete(season, np.s_[::2])) # remove every 2nd (a slice)
print(np.delete(squad, 0, axis=0)) # drop the first row
print(np.delete(squad, 1, axis=1)) # drop the 2nd column
print(season) # original unchangedtext
[ 72 45 88 31 64 103]
[ 45 31 0 103]
[45 31 0]
[[56 0 74]]
[[72 88]
[56 74]]
[ 72 45 88 31 64 0 103]Tip:
np.deleteremoves by position. To remove by value (e.g. all ducks), use a boolean mask:season[season != 0]→[ 72 45 88 31 64 103].
Why they are slow in loops
python
import time
n = 20000
start = time.perf_counter()
arr = np.array([], dtype=int)
for i in range(n):
arr = np.append(arr, i) # copies the whole array every time
t1 = time.perf_counter() - start
start = time.perf_counter()
lst = []
for i in range(n):
lst.append(i) # list grows in place
arr2 = np.array(lst) # convert ONCE
t2 = time.perf_counter() - start
start = time.perf_counter()
arr3 = np.empty(n, dtype=int) # preallocate
for i in range(n):
arr3[i] = i
t3 = time.perf_counter() - startOne run on a laptop (your numbers will differ, the ratio won't):
text
np.append in a loop : 0.0662 s
list.append + array : 0.0020 s
preallocate + fill : 0.0020 sHow it works: the k-th np.append copies k values, so n appends copy about n²/2 values in total — quadratic time. List append is amortised O(1). For 20,000 items that is already ~30× slower; for a million items it can take minutes.
| Situation | Best approach |
|---|---|
| Collecting results in a loop | Python list.append, then np.array(list) once |
| Final size known in advance | np.empty(n) / np.zeros(n) and fill by index |
| Joining a few big pieces | np.concatenate([...]) once |
| Removing values by condition | boolean mask arr[mask] |
Python list vs NumPy
| Python list | NumPy array | |
|---|---|---|
append | lst.append(x) — in place, returns None | np.append(arr, x) — returns a new array |
insert | lst.insert(i, x) — in place | np.insert(arr, i, x) — new array |
| delete | del lst[i] / lst.pop(i) — in place | np.delete(arr, i) — new array |
| cost of adding 1 item | usually O(1) | always O(n) (full copy) |
Common mistakes
- ❌
np.append(scores, 31)and expectingscoresto change. ✅scores = np.append(scores, 31). - ❌
scores.append(31). ✅ NumPy arrays have no.appendmethod →AttributeError. - ❌ Forgetting
axison a 2D array and getting a flattened 1D result. ✅ Always passaxis=0/axis=1for tables. - ❌ Growing an array with
np.appendinside a loop. ✅ Use a list, or preallocate.
Interview tip
Q: Why is np.append inside a loop considered an anti-pattern?
A: NumPy arrays are fixed-size contiguous blocks, so every np.append allocates a new array and copies all existing elements. n appends cost O(n²). Collect values in a Python list and convert once, or preallocate with np.empty and fill by index.
Key points to remember
- np.append, np.insert and np.delete never modify the input — they return a new array that you must assign.
- Without an axis, all three flatten a 2D array to 1D first; pass axis=0 (rows) or axis=1 (columns) for tables.
- np.append with an axis behaves like concatenate — values must have the same number of dimensions ([[...]]).
- np.insert puts values before the given index; np.delete removes by index, list of indices or slice (np.s_[::2]).
- To remove by value, use a boolean mask such as arr[arr != 0] instead of np.delete.
- Each call copies the entire array, so using them in a loop is O(n²) — collect in a list or preallocate instead.
- NumPy arrays have no .append() method — calling it raises AttributeError.
Try it yourself
append, insert, delete — originals stay unchanged
Why np.append in a loop is slow
Practice: clean up a season
Revision Flashcards
Tap a card to flip it and see the answer.
