6

I have a problem with the simple program below :

def my_function(my_array = np.zeros(0)):
    my_array = [1, 2, 3]

my_array = np.zeros(0)
my_function(my_array)
print my_array

It prints an empty array as if my_array was passed by copy and not by reference inside the function. How to correct that ?

Vincent
  • 57,703
  • 61
  • 205
  • 388

3 Answers3

17

The pass-by-reference model is more of a pass-by-value of a pointer. So inside your my_function you have a copy of a pointer to your original my_array. If you were to use that pointer to manipulate the inputed array directly that would make a change, but a re-assignment of the copied pointer won't affect the original array.

As an example:

def my_func(a):
    a[1] = 2.0

ar = np.zeros(4)
my_func(ar)
print ar

The above code will change the internal value of ar.

Ramón J Romero y Vigil
  • 17,373
  • 7
  • 77
  • 125
9

You can use slice assignment here just like you would a list:

def func(my_array):
    my_array[:3] = [1,2,3]

Note that this still requires that my_array has at least 3 elements in it ... Example usage:

>>> def func(my_array):
...     my_array[:3] = [1,2,3]
... 
>>> a = np.zeros(4)
>>> a
array([ 0.,  0.,  0.,  0.])
>>> func(a)
>>> a
array([ 1.,  2.,  3.,  0.])

The thing you're missing is how python deals with references. When you enter my_function, you have a reference to the original ndarray object bound to the name my_array. However, as soon as you assign something new to that name, you lose your original reference and replace it with a reference to a new object (in this case, a list).

Note that having a default argument which is a mutable object can often lead to surprises

Community
  • 1
  • 1
mgilson
  • 300,191
  • 65
  • 633
  • 696
  • 1
    I wonder if there's a neat way to avoid the `:3`. If the input array had, say, ten elements, then this code would not do what I suspect the OP would expect from his code. – NPE Mar 04 '13 at 15:26
  • 1
    This doesn't actually work - try `a = np.zeros(0)` and `a[:3] = [1,2,3]` – YXD Mar 04 '13 at 15:28
  • @MrE -- Sure. I suppose I'm assuming that OP is actually going to pass in an argument that is large enough to handle the RHS in the calculation. – mgilson Mar 04 '13 at 15:29
6

np.zeros(0) gives you an empty numpy array. The reference inside your function now points to a new Python list but you haven't actually modified your empty numpy array, so that's still what you're printing out.

Recommend to read this answer to clear up some concepts.

Community
  • 1
  • 1
YXD
  • 31,741
  • 15
  • 75
  • 115
  • I do not understand why when I print the array inside the function it works well, but not outside... – Vincent Mar 04 '13 at 15:30
  • You should read the first answer here http://stackoverflow.com/questions/986006/python-how-do-i-pass-a-variable-by-reference – YXD Mar 04 '13 at 15:31