Accidental sharing causes spooky bugs; accidental copying wastes memory. You need to predict both.
A view is a new array object that looks at the same data buffer as another array, possibly with different shape, strides or offset. A copy has its own buffer. Changing a view changes the original; changing a copy does not.
The rules of thumb:
- Views: basic slicing (
a[1:5],a[:, 0],a[::2]),reshape(when possible),ravel(when possible),.T,transpose,a.view(dtype),np.broadcast_to. - Copies: fancy indexing (
a[[1, 2]]), boolean masks (a[a > 0]), arithmetic results,astype,flatten,np.array(a),a.copy(). - Neither: plain assignment
b = acreates no new array at all, only a second name for the same object.
"When possible" matters. reshape returns a view if the existing memory layout allows it; reshaping a transposed or step-sliced array may silently copy. If you need a guarantee, check rather than assume.
How to check:
b.base is ais True whenbis a view whose memory belongs toa; a copy hasbase is None.np.shares_memory(a, b)gives an exact answer (it can be slow);np.may_share_memoryis a quick conservative test.
A classic bug: you slice a small window out of a huge array and keep it around. The view keeps the entire original buffer alive, so memory never gets freed. Call .copy() on small pieces you keep long-term.
Functions that take an input and modify it in place (like a.sort() or np.copyto) change every view of that data too. When writing functions, avoid surprising callers: either document in-place behaviour or work on a copy.
Example
import numpy as np
a = np.arange(6)
s = a[1:4] # view
f = a[[1, 2, 3]] # copy (fancy index)
r = a.reshape(2, 3) # view
print(s.base is a, f.base is None) # True True
print(np.shares_memory(a, r)) # True
s[0] = 100
f[1] = -1
print(a) # [ 0 100 2 3 4 5] only s affected
t = r.T # view, not contiguous
flat = t.reshape(-1) # layout forces a copy here
print(np.shares_memory(flat, a)) # False
big = np.zeros(10_000_000)
keep = big[:10].copy() # lets 'big' be freed later
del bigRemember
- Basic slices, reshape, transpose and
.viewgive views - Fancy indexing, boolean masks, arithmetic and
astypegive copies b = acopies nothing; it's the same object- Check with
.baseornp.shares_memorywhen unsure
Watch out for
- Keeping a tiny slice of a huge array alive, which pins the whole buffer in memory.