1

I am not very sure how to explain this question, but lets look at the code below:

import numpy as np

def glb_mod(s_np,s):
    s_np.shape = (2,-1)
    s=2
    return s

if __name__=='__main__':
    a=1
    a_np = np.arange(10)
    print ('a, a_np initialized as')
    print(a , a_np)
    glb_mod(a_np,a)
    print ('a, a_np are now')
    print (a, a_np)

I have two global variables named:

 a, a_np

after run through the function

glb_mod()

results:
 a, a_np initialized as
 1 [0 1 2 3 4 5 6 7 8 9]
 a, a_np are now
 1 [[0 1 2 3 4]
 [5 6 7 8 9]]

why "a_np" changed but "a" not change? Just wonder how should I modify the code so that when passing global variable "a_np" into function, "a_np" will not change after run throw the function "glb_mod()"?

DIY-DS
  • 243
  • 4
  • 16
  • As to why it does not change `a`: https://stackoverflow.com/questions/15148496/passing-an-integer-by-reference-in-python, for your array you can have a look here: https://docs.scipy.org/doc/numpy-1.14.0/reference/generated/numpy.copy.html – NOhs Mar 14 '18 at 17:33
  • Your second parameter to the `glb_mod` function has no effect because that variable is reassigned with `s=2`. – Alexander Mar 14 '18 at 17:34

2 Answers2

3

This happens because in Python most types of data are passed by reference, not by value. That is, the function gets the address of the data, not a copy of said data.

This is useful because it saves a lot of space as you don't copy huge amounts of data every time you call a function, you just copy the address. On the other hand, it can cause seemingly weird stuff to happen, as in your case, but you can use that to your advantage most of the time.

NumPy arrays are passed by reference, which means the array isn't copied, and s_np inside glb_mod is the same object as a_np.

Integers, however, are always passed by value, that is, copied to the function.

If you don't want your function to modify your original array, copy it manually:

glb_mod(a_np.copy(), a)
ForceBru
  • 43,482
  • 10
  • 63
  • 98
3

Because s_np is mutable and you are modifying s_np in-place.

s on the other hand is immutable, and even if it were mutable, the assignment s=2 will make it change only on a local scope.

You should use

a = glb_mod(a_np,a)

instead, since you're returning s.

If you do not want s_np to change, you should pass a copy to the function.

To be on the save side, you can use

import copy

glb_mod(copy.deepcopy(a_np), a)
Mike Scotty
  • 10,530
  • 5
  • 38
  • 50
  • Great explanation, and advice, except maybe at the end—if it's a numpy array, it's probably clearer and more idiomatic to use the numpy API to copy it than to the copy module. – abarnert Mar 14 '18 at 17:39