Are numpy arrays passed by reference?

Viewed 49672

I came across the fact that numpy arrays are passed by reference at multiple places, but then when I execute the following code, why is there a difference between the behavior of foo and bar

import numpy as np

def foo(arr):
   arr = arr - 3

def bar(arr):
   arr -= 3

a = np.array([3, 4, 5])
foo(a)
print a # prints [3, 4, 5]

bar(a)
print a # prints [0, 1, 2]

I'm using python 2.7 and numpy version 1.6.1

3 Answers

Python passes the array by reference:

$:python
...python startup message

>>> import numpy as np
>>> x = np.zeros((2,2))
>>> x
array([[0.,0.],[0.,0.]])
>>> def setx(x):
...    x[0,0] = 1
...
>>> setx(x)
>>> x
array([[1.,0.],[0.,0.]])

The top answer is referring to a phenomenon that occurs even in compiled c-code, as any BLAS events will involve a "read-onto" step where either a new array is formed which the user (code writer in this case) is aware of, or a new array is formed "under the hood" in a temporary variable which the user is unaware of (you might see this as a .eval() call).

However, I can clearly access the memory of the array as if it is in a more global scope than the function called (i.e., setx(...)); which is exactly what "passing by reference" is, in terms of writing code.


And let's do a few more tests to check the validity of the accepted answer:

(continuing the session above)
>>> def minus2(x):
...    x[:,:] -= 2
...
>>> minus2(x)
>>> x
array([[-1.,-2.],[-2.,-2.]])

Seems to be passed by reference. Let us do a calculation which will definitely compute an intermediate array under the hood, and see if x is modified as if it is passed by reference:

>>> def pow2(x):
...    x = x * x
...
>>> pow2(x)
>>> x
array([[-1.,-2.],[-2.,-2.]])

Huh, I thought x was passed by reference, but maybe it is not? -- No, here, we have shadowed the x with a brand new declaration (which is hidden via interpretation in python), and python will not propagate this "shadowing" back to global scope (which would violate the python-use case: namely, to be a beginner level coding language which can still be used effectively by an expert).

However, I can very easily perform this operation in a "pass-by-reference" manner by forcing the memory (which is not copied when I submit x to the function) to be modified instead:

>>> def refpow2(x):
...    x *= x
...
>>> refpow2(x)
>>> x
array([[1., 4.],[4., 4.]])

And so you see that python can be finessed a bit to do what you are trying to do.

Related