bcf
bcf

Reputation: 2134

Shallow Copy of ndarray to function

If I have a list x = [1, 2, 3] and pass it to a function f which uses the operator += in the form f(x[:]), a shallow copy is made and the contents are unchanged:

def f(x):
    print "f, x = ", x, ", id(x) = ", id(x)
    x += [1]
    print "f, x = ", x, ", id(x) = ", id(x)

x = [1,2,3]
print "x = ", x, ", id(x) = ", id(x)
f(x[:])
print "x = ", x, ", id(x) = ", id(x)

Output:

x =  [1, 2, 3] , id(x) =  139701418688384
f, x =  [1, 2, 3] , id(x) =  139701418790136
f, x =  [1, 2, 3, 1] , id(x) =  139701418790136
x =  [1, 2, 3] , id(x) =  139701418688384

However, expecting the same behavior for an ndarray x = np.array([1, 2, 3]) I was surprised that the contents were changed, even though a copy was indeed made:

import numpy as np

def f(x):
    print "f, x = ", x, ", id(x) = ", id(x)
    x += [1]
    print "f, x = ", x, ", id(x) = ", id(x)

x = np.array([1,2,3])
print "x = ", x, ", id(x) = ", id(x)
f(x[:])
print "x = ", x, ", id(x) = ", id(x)

Output:

x =  [1 2 3] , id(x) =  139701418284416
f, x =  [1 2 3] , id(x) =  139701418325856
f, x =  [2 3 4] , id(x) =  139701418325856
x =  [2 3 4] , id(x) =  139701418284416

(I know the +[1] function acts differently for an ndarray vs a list). How can I pass an ndarray like the list and avoid this behavior?

Bonus question Why is the problem resolved by using x = x + [1] in the function f?

Upvotes: 2

Views: 490

Answers (1)

MSeifert
MSeifert

Reputation: 152725

You can use the copy method of the numpy-array if you want a copy:

f(x.copy())

Note that even though the id of x and x[:] differs these arrays may share the same memory so changes to one will propagate to the other and vice-versa:

x = np.array([1,2,3])
y = x[:]
np.may_share_memory(x, y)   # True

z = x.copy()
np.may_share_memory(x, z)   # False

However normally you don't pass copies to a function. You would create a copy inside the function:

def give_me_a_list(lst):
    lst = list(lst)  # makes a shallow copy
    # ...


def give_me_an_array(arr):
    arr = np.array(arr)  # makes a copy at least if you don't pass in "copy=False".
    # ...

Upvotes: 3

Related Questions