Reputation: 1007
I have a problem with slicing an array. The problem is that if I do some operation inside of function and return modified array my array outside of function is also changed. I could not really understand that behavior of numpy slicing opration on array.
Here is the code:
import numpy as np
def do_smth(a):
x = np.concatenate((a[..., 1], a[..., 3]))
y = np.concatenate((a[..., 2], a[..., 4]))
xmin, xmax = np.floor(min(x)), np.ceil(max(x))
ymin, ymax = np.floor(min(y)), np.ceil(max(y))
a[..., 1:3] = a[...,1:3] - np.array([xmin, ymin])
a[..., 3:5] = a[...,3:5] - np.array([xmin, ymin])
return a
def main():
old_a = np.array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14]])
new_a = do_smth(old_a)
print "new_a:\n", new_a, '\n\n'
print "old_a:\n", old_a
gives output:
new_a:
[[ 0 0 0 2 2]
[ 5 5 5 7 7]
[10 10 10 12 12]]
old_a:
[[ 0 0 0 2 2]
[ 5 5 5 7 7]
[10 10 10 12 12]]
Can anyone tell why old_a
has been changed? And how can I make old_a
unchanged?
Thank you
Upvotes: 0
Views: 116
Reputation: 353
The problem is not slicing the array, but the fact that numpy arrays are mutable objects.
This means that, whenever you make something like
import numpy as np
a = np.array([1,2,3,4])
b = a
the object b
is a view of array a
, more precisely, b
is just another name for a
.
Note that, when you pass a mutable python object (like a python list or dict) to a function that do some operation that changes this object, the original object passed is also changed. This is how python (not only numpy) treats mutable objects.
to get the feeling you can do something like this:
from __future__ import print_funtion
import numpy as np
a = np.ones(3)
b = a
c = [1,1,1]
d = c
print("a before:", a)
print("b before:", b)
print("c before:", c)
print("c before:", d)
def change_it(x):
x[0] = 10
change_it(a)
change_it(c)
print("a after:", a)
print("b after:", b)
print("c after:", c)
print("c after:", d)
which gives:
a before: [ 1. 1. 1.]
b before: [ 1. 1. 1.]
c before: [1, 1, 1]
d before: [1, 1, 1]
a after: [ 10. 1. 1.]
b after: [ 10. 1. 1.]
c after: [10, 1, 1]
d after: [10, 1, 1]
Note that the function change_it
doesn't even return anything and was only used
on a
and c
but also changed b
and d
If you want to avoid this, you must use an explicit copy of your array.
That is easily done by:
def do_smth(original_a): # change the argument name
a = original_a.copy() # make an explicit copy
x = np.concatenate((a[..., 1], a[..., 3]))
y = np.concatenate((a[..., 2], a[..., 4]))
xmin, xmax = np.floor(min(x)), np.ceil(max(x))
ymin, ymax = np.floor(min(y)), np.ceil(max(y))
a[..., 1:3] = a[...,1:3] - np.array([xmin, ymin])
a[..., 3:5] = a[...,3:5] - np.array([xmin, ymin])
return a
Upvotes: 2
Reputation: 105
Although values in Python are passed by assignment, the object you are sending in is actually a reference to a memory location. So thus, when you change the object in the function you are altering the same variable you sent into the function.
You will want to clone the object first, and then do your operations on the copy.
Upvotes: 2