简体   繁体   中英

Python function not supposed to change a global variable

I am fairly new to Python and Numpy, and I encountered this issue when translating a MATLAB program into Python.

As far as I can tell, the code below is behaving abnormally by modifying a global variable even though it shouldn't.

import numpy as np

A = np.matrix([[0, 1, 2], [3, 4, 5], [6, 7, 8]])

def function(B):
    B[1,1] = B[1,1] / 2
    return B

C = function(A)

print(A)

The output is:

[[0 1 2]
 [3 2 5]
 [6 7 8]]

The function divides the middle number of the matrix by two and returns it. But it seems it is also altering the global variable.

Here, the issue can easily be avoided but I am trying to understand why it arises.

For some reasons, this does NOT happen if the function divides the WHOLE matrix by 2.

import numpy as np

A = np.matrix([[0, 1, 2], [3, 4, 5], [6, 7, 8]])

def function(B):
    B = B / 2
    return B

C = function(A)

print(A)

The output is:

[[0 1 2]
 [3 4 5]
 [6 7 8]]

In the first case

def function(B):
    B[1,1] = B[1,1] / 2
    return B

you alter the content of a specific element of the mutable object pointed to by the name B . As described in the previous answer already.

Whereas, in

def function(B):
    B = B / 2
    return B

the point is that B / 2 is a new object altogether. The object given as input is not altered.

The fact that you reassign it to the local name B is unimportant. It makes B no longer point to the orginal object provided as input to the function, but to a completely new object instance. That the function returns.

So, correctly, the object instance pointed to by the name A is unaffected, even if mutable.

In contrast to MATLAB, Python is a pass by reference language. Normally a function is given a reference to each of the arguments. If the function then modifies an argument, eg B[1,1]=... , the change is reflected in the argument.

http://www.mathworks.com/matlabcentral/answers/152-can-matlab-pass-by-reference is an explanation of MATLAB's distinction between passing arguments by handle v. by value. In effect, Python/numpy passes by handle.

According to this answer, B(1,1) = B(1,1)/2 in MATLAB would force a copy, so that B no longer shares a reference with A . In Python , such an action modifies the calling argument, without making a copy. That it occurs within a function does not matter.

When you have B[1,1] = B[1,1]/2 you are modifying an element of a mutable data structure -- which mutates the data structure. In B = B / 2 you are reassigning B in the local scope to point to something else. That change doesn't persist when you exit the local scope.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM