Copies vs Views

A view is a NumPy array that shares the same memory as another array, while a copy is an independent array with its own memory — and knowing which one you have is the key to avoiding accidental data corruption.

Learn Copies vs Views in our free NumPy course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick reference.

Part of the free Numpy course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

In this lesson you'll see how slicing returns a memory-sharing view, how .copy() breaks that link, how to inspect the .base attribute, and why fancy and boolean indexing always return copies.

When you slice a NumPy array with arr[1:4] , you do not get a fresh copy of the data. You get a view — a lightweight window onto the same underlying memory. This is fast and saves memory, but it has a surprising consequence: writing through the view changes the original.

Expected output: the view [20 30 40] , then after assignment the view is [999 30 40] and the original becomes [10 999 30 40 50] .

This view behavior is the single most common source of confusing bugs for NumPy beginners. You pull out a slice, modify it thinking it is separate, and silently mutate your source data.

Expected output: the original matrix is now [[0 0 0] [4 5 6]] — zeroing the row view changed the source.

The fix is simple: call .copy() to allocate fresh memory. A copy is fully independent — editing it never touches the original. The .base attribute lets you confirm which kind you have: a view's .base points back to its parent, while a copy's .base is None .

Expected output: [999 30 40] for the copy, the original unchanged as [10 20 30 40 50] , then True for the view's base and None for the copy's base.

Not every selection shares memory. Fancy indexing (using a list of integer positions) and boolean indexing (using a True/False mask) always return a copy . Meanwhile, reshape usually returns a view because it just reinterprets the same data with a new shape.

Expected output: [-1 30 50] with arr unchanged, the mask result [30 40 50] with base of None , and True showing reshape gives a view.

Replace each ___ so editing the slice does NOT change the original array.

Expected output: [99 2 3] , the original still [1 2 3 4 5] , and None . (Answers: copy , None .)

❌ My original array changed when I only edited a slice

The slice was a view sharing memory with the source.

✅ Fix: call .copy() on the slice to get an independent array before modifying it.

❌ Expected fancy indexing to update the original

Storing arr[[0, 2]] in a new variable gives a copy, so edits to it do nothing to arr .

✅ Fix: assign directly back, e.g. arr[[0, 2]] = 0 , to change the original in place.

Create one slice as a view and one as a copy, change both, and prove that only the view affected the original.

Lesson 13 complete — no more memory surprises!

You now know that slices are views, .copy() makes independent arrays, .base reveals the link, and fancy and boolean indexing always copy. The classic gotcha can't catch you anymore.

🚀 Up next: Random Number Generation — generate reproducible random data with the modern Generator API.

Practice quiz

What is a view in NumPy?

  • A read-only array
  • A new array sharing the same memory as the original
  • An independent copy of the data
  • A 1D version of an array

Answer: A new array sharing the same memory as the original. A view shares memory, so changing one changes the other.

What does basic slicing like arr[1:4] return?

  • A view that shares memory
  • A copy
  • A scalar
  • An error

Answer: A view that shares memory. Basic slicing returns a memory-sharing view of the original.

If view = original[1:4] and you set view[0] = 999, what happens to original?

  • It raises an error
  • Nothing changes
  • The corresponding element of original also changes
  • original is deleted

Answer: The corresponding element of original also changes. Because the slice is a view, writing through it mutates the original.

How do you make an independent slice that does not affect the original?

.copy() allocates fresh memory so edits stay isolated.

For a view v of array a, what is v.base?

  • None
  • The original array a
  • An empty list
  • 0

Answer: The original array a. A view's .base points back to the array it shares memory with.

What is the .base of an array returned by .copy()?

  • None
  • The original array
  • Itself
  • True

Answer: None. A copy owns its data, so its .base is None.

Does fancy indexing like arr[[0, 2, 4]] return a copy or a view?

  • A view
  • It depends on the dtype
  • A copy
  • Neither; it errors

Answer: A copy. Fancy indexing always returns a new copy.

Does boolean indexing like arr[arr > 25] return a copy or a view?

  • A view
  • A scalar
  • Nothing
  • A copy

Answer: A copy. Boolean (mask) indexing always returns a copy.

What does arr.reshape(5, 1) usually return?

  • A scalar
  • A view of the same data
  • A copy
  • An error

Answer: A view of the same data. reshape usually returns a view because it reinterprets the same buffer.

How can you confirm two arrays share memory?

  • np.shares_memory(a, b)
  • a == b
  • a.copy()
  • len(a)

Answer: np.shares_memory(a, b). np.shares_memory tests whether the arrays overlap in memory.