Copy Operations¶
These operations create independent copies with separate memory.
Mental Model
A copy is an entirely new array with its own memory -- modifying the copy never affects the original. Use .copy() when you need to detach from shared memory, especially after slicing. The cost is double the memory and an O(n) data transfer, so copy only when you truly need independence.
Copy = New Buffer (O(n))
Every copy operation allocates a new data buffer and transfers all elements — an O(n) operation in both time and memory. This is the fundamental cost: views are O(1) because they reuse the existing buffer; copies are O(n) because they duplicate it. Knowing which operations trigger copies lets you avoid unnecessary allocations in performance-sensitive code.
Method copy¶
The .copy() method creates an explicit copy.
1. Slice then Copy¶
```python import numpy as np
def main(): x = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) print(f"{x = }")
y = x[1:4].copy() # returns copy
y[0] = -1
print(f"{x = }")
if name == "main": main() ```
Output:
x = array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
x = array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
2. Original Unchanged¶
The copy is independent; mutations don't propagate.
Function np.copy¶
The np.copy() function creates a copy.
1. np.copy Usage¶
```python import numpy as np
def main(): x = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) print(f"{x = }")
y = np.copy(x[1:4]) # returns copy
y[0] = -1
print(f"{x = }")
if name == "main": main() ```
Output:
x = array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
x = array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
2. Equivalent to Method¶
Both approaches produce identical results.
Fancy Indexing¶
Fancy indexing always returns a copy.
1. Index Array¶
```python import numpy as np
def main(): x = np.array([0, 1, 2, 3, 4, 5]) y = x[[0, 2, 4]] # fancy indexing returns copy y[0] = -1 print(f"{x = }")
if name == "main": main() ```
Output:
x = array([0, 1, 2, 3, 4, 5])
2. Boolean Indexing¶
```python import numpy as np
def main(): x = np.array([0, 1, 2, 3, 4, 5]) y = x[x > 2] # boolean indexing returns copy y[0] = -1 print(f"{x = }")
if name == "main": main() ```
Output:
x = array([0, 1, 2, 3, 4, 5])
Arithmetic Operations¶
Most arithmetic creates new arrays.
1. Addition¶
```python import numpy as np
x = np.array([1, 2, 3]) y = x + 1 # creates new array y[0] = -1 print(f"{x = }") # x = array([1, 2, 3]) ```
2. Multiplication¶
```python import numpy as np
x = np.array([1, 2, 3]) y = x * 2 # creates new array ```
3. In-place Operations¶
Use +=, *= to modify in-place without creating copies.
Copy Summary¶
Operations that create copies.
1. Explicit Copies¶
.copy()methodnp.copy()function
2. Implicit Copies¶
- Fancy indexing:
arr[[0, 2, 4]] - Boolean indexing:
arr[arr > 0] - Arithmetic:
arr + 1,arr * 2 - Some reshapes (non-contiguous)
3. Best Practice¶
When in doubt, use .copy() explicitly for clarity.
Exercises¶
Exercise 1.
Create an array a = np.arange(10). Make a copy using b = a.copy(). Modify b[0] = 999 and verify that a is unchanged. Check that b.base is None (confirming it owns its data).
Solution to Exercise 1
import numpy as np
a = np.arange(10)
b = a.copy()
b[0] = 999
print(f"a[0] = {a[0]}") # 0 (unchanged)
print(f"b.base is None: {b.base is None}") # True
Exercise 2.
Given a = np.arange(12).reshape(3, 4), create three copies using a.copy(), np.array(a, copy=True), and np.copy(a). Modify each copy and verify all are independent from a.
Solution to Exercise 2
import numpy as np
a = np.arange(12).reshape(3, 4)
c1 = a.copy()
c2 = np.array(a, copy=True)
c3 = np.copy(a)
c1[0, 0] = 100
c2[0, 0] = 200
c3[0, 0] = 300
print(f"a[0, 0] = {a[0, 0]}") # 0 (unchanged)
Exercise 3.
Demonstrate that boolean indexing always returns a copy: create a = np.arange(10), extract b = a[a > 5], modify b, and show a is not affected. Contrast this with slice indexing which returns a view.
Solution to Exercise 3
import numpy as np
a = np.arange(10)
b = a[a > 5] # boolean indexing -> copy
b[0] = 999
print(f"a after boolean mod: {a}") # unchanged
c = a[2:5] # slice -> view
c[0] = 888
print(f"a after slice mod: {a}") # a[2] changed to 888