NumPy: Copies and Views

Last updated: 2026-08-26

Charlie modified a sub-array and found the original had changed too — he spent 2 hours debugging. Alice says: "Check the .base attribute. If base is the original array, it's a view. When in doubt, .copy()."

This story highlights a critical issue: not all NumPy operations return independent arrays. Understanding the difference between views and copies is essential to avoiding subtle data modification bugs.


1. The View Mechanism

(1) What Is a View

A view is another "window" into the original array — it shares the same memory. Modifying a view directly modifies the original array.

PYTHON
import numpy as np

a = np.array([1, 2, 3, 4, 5])
b = a[1:4]          # slice returns a view
b[0] = 999
print(a)            # [  1 999   3   4   5]  original changed!
print(b)            # [999   3   4]
TEXT 📖 Display only
> **Output:** Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.

The advantage of views is zero-copy — no extra memory, extremely fast.

(2) Memory Relationship

PYTHON
a = np.array([10, 20, 30])
b = a[:]            # view
print(a.__array_interface__['data'][0])  # original data address
print(b.__array_interface__['data'][0])  # view data address (same!)
TEXT 📖 Display only
> **Output:** Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.

Both point to the same memory start address — only the metadata (shape, strides) differs.

(3) The .base Attribute

PYTHON
a = np.arange(12).reshape(3, 4)
b = a[0:2, 1:3]  # slice view
c = a[[0, 2]]    # fancy indexing — copy

print(b.base is a)  # True — view
print(c.base is a)  # False — copy


2. Which Operations Return Views vs Copies

(1) Views (shared memory, no copy)

Operation Example
Basic slicing a[1:5], a[1:5:2], a[:, 2:4]
.view() a.view(np.float32)
reshape a.reshape(3, 4)
transpose / .T a.T, a.transpose(1, 0)
ravel (usually) a.ravel()
squeeze a.squeeze()
newaxis a[:, np.newaxis]

(2) Copies (new memory, independent)

Operation Example
.copy() a.copy()
Fancy indexing a[[0, 2, 4]]
Boolean indexing a[a > 0]
astype a.astype(np.float32)
flatten a.flatten()
np.where np.where(a > 0, a, 0)

▶ Example

TEXT 📖 Display only
> **Output:** Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.

: Verify view vs copy with .base (Difficulty ⭐)

PYTHON
import numpy as np

a = np.arange(12).reshape(3, 4)

# Basic slice — view
b = a[0:2]
print(f"slice base is a: {b.base is a}")  # True

# Reshape — view
c = a.reshape(6, 2)
print(f"reshape base is a: {c.base is a}")  # True

# Fancy indexing — copy
d = a[[0, 2]]
print(f"fancy base is a: {d.base is a}")  # False

# Boolean indexing — copy
e = a[a > 5]
print(f"boolean base is a: {e.base is a}")  # False
TEXT 📖 Display only
> **Output:** Run NumPy 2.x in your local Python environment to see the ndarray output. The Piston server does not have NumPy pre-installed — install it locally (`pip install numpy`) and compare. Actual values may vary by NumPy version and random seed.
⚠️ Note: The code below needs to run in a local Python environment.



3. Comparison Tables

(1) View vs Copy Decision Tree

TEXT 📖 Display only
Is it a basic slice (start:stop:step)?
  ├── Yes → View (shared memory)
  └── No → Is it fancy/boolean indexing?
      ├── Yes → Copy (new memory)
      └── No → Check .base attribute
```text

### (2) Performance Impact

| Operation | Time (1M elements) | Memory |
|-----------|-------------------|--------|
| View (slice) | O(1) | Shared |
| Copy (fancy) | O(n) | New allocation |
| .copy() | O(n) | New allocation |
| astype | O(n) | New allocation |
### ▶ Example: Reshape and transpose return views (Difficulty ⭐⭐)

```python
import numpy as np

a = np.arange(12).reshape(3, 4)

# Reshape returns a view
b = a.reshape(6, 2)
print(f"reshape base is a: {b.base is a}")

# Transpose returns a view
c = a.T
print(f"transpose base is a: {c.base is a}")

# Modifying the view changes the original
c[0, 0] = 999
print(f"a[0, 0] after transpose mod: {a[0, 0]}")

Output:

TEXT 📖 Display only
reshape base is a: True
transpose base is a: True
a[0, 0] after transpose mod: 999

▶ Example: flatten vs ravel — copy vs view (Difficulty ⭐⭐)

PYTHON
import numpy as np

a = np.arange(12).reshape(3, 4)

# ravel usually returns a view
r = a.ravel()
print(f"ravel base is a: {r.base is a}")

# flatten always returns a copy
f = a.flatten()
print(f"flatten base is a: {f.base is a}")

# After transpose, ravel may need to copy
t = a.T
r2 = t.ravel()
print(f"ravel of transposed base is a: {r2.base is a}")

Output:

TEXT 📖 Display only
ravel base is a: True
flatten base is a: False
ravel of transposed base is a: False


❓ FAQ

Q How do I check if an array is a view of another?
A Check arr.base is original. If True, it's a view. If arr.base is None, it owns its own data.
Q Can I create a view with a different dtype?
A Yes — a.view(np.float32) reinterprets the same bytes as a different type. This is dangerous and rarely needed. Use astype for a safe copy with conversion.
Q Why does ravel sometimes return a copy?
A ravel returns a view only if the array is contiguous in memory. After operations like transpose, the array may be non-contiguous, and ravel falls back to a copy.
Q When should I use .copy()?
A (1) When you're about to modify a sub-array and don't want to affect the original, (2) when you need a contiguous array for a C-level operation, (3) when you want to break the memory link explicitly.

📖 Summary



📝 Exercises

  1. Beginner (Difficulty ⭐): Create a 1D array of 10 elements. Create a slice, a fancy index, and a boolean mask selection. For each, check if modifying the result changes the original.

  2. Intermediate (Difficulty ⭐⭐): Create a 3x4 array, take a 2x2 slice, and modify it. Observe the original changing. Now use .copy() and repeat — confirm the original stays unchanged.

  3. Advanced (Difficulty ⭐⭐⭐): Create a 3D array, transpose it, then try to reshape the result. Check if the reshape returns a view (use .base). Explain why or why not.

Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏