Reputation: 192
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 12
s 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 12
s in arr
do not become 6
).
Why does this happen? What makes s = s // 2
different?
Upvotes: 13
Views: 5232
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
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