Vlad Dinu
Vlad Dinu

Reputation: 192

Confusion about when NumPy array slices are references and when they are copies

If I try the following:

>>> import numpy as np
>>> arr = np.arange(10)
>>> s = arr[2:5]
>>> s[:] = 12
>>> s, arr
(array([12, 12, 12]), array([ 0,  1, 12, 12, 12,  5,  6,  7,  8,  9]))
>>> s = s // 2
>>> s, arr
(array([6., 6., 6.]), array([ 0,  1, 12, 12, 12,  5,  6,  7,  8,  9]))

It seems that the first time around s is just a reference to part of arr, so modifying it also changes the array (some 12s appear in arr); but the second time around, s has become a copy of that part of the array, and arr is not affected (the 12s in arr do not become 6).

Why does this happen? What makes s = s // 2 different?

Upvotes: 13

Views: 5232

Answers (2)

BENY
BENY

Reputation: 323276

Use [:] to assign the values back:

>>> arr = np.arange(10)
>>> s = arr[2:5]
>>> s[:] = 12
>>> print(arr)
[ 0  1 12 12 12  5  6  7  8  9]
>>> s[:] = s // 2
>>> print(arr)
[0 1 6 6 6 5 6 7 8 9]

Upvotes: 2

user2699
user2699

Reputation: 3147

Slicing a Numpy array always returns a view (reference) of an array. Modifying the slice will modify the original array.

In your second example you re-assign to the name s. That does not modify the object. A new array is created to represent the result of s // 2 - which has no relationship to the original arr - and then s becomes a name for that new array.

To modify s in-place, use an augmented assignment operator, such as //=, or (as you have already seen) slice assignment such as with [:]:

>>> import numpy as np
>>> arr = np.arange(10)
>>> s = arr[2:5]
>>> s, arr
(array([2, 3, 4]), array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]))
>>> s[:] = 12 # modifies the slice, and therefore the original
>>> s, arr
(array([12, 12, 12]), array([ 0,  1, 12, 12, 12,  5,  6,  7,  8,  9]))
>>> s //= 2 # modifies the slice, and therefore the original
>>> s, arr
(array([6, 6, 6]), array([0, 1, 6, 6, 6, 5, 6, 7, 8, 9]))
>>> s = s // 2 # makes a new slice (and reassigns the name), so the original is untouched
>>> s, arr
(array([3, 3, 3]), array([0, 1, 6, 6, 6, 5, 6, 7, 8, 9]))

Upvotes: 11

Related Questions