Global Scope when accessing array element inside f

2019-08-29 07:28发布

问题:

When I assign a value into an array the scope of the variable remain local (see loc()). However if I access the element of an array the scope becomes global ( see glob())

import numpy as np
M = np.array([1])
def loc():
    M = 2
    return 0
def glob():
    M[0] = 3
    return 0

loc()
print M
>>> [1]

glob()
print M
>>> [3]

Why does this happen ? How can i locally modify the elements of an array without modifying the array globally? I need to have a loop inside my function changing one element at a time.

回答1:

You're mixing several things here.

First of all, M = 2 creates a local variable named M (you can see it in locals()) and prevents you from accessing the original M later on (although you're not doing it... But just to make a point). That's sometimes referred to as "shadowing".

Second of all, the np.array is a mutable object (the opposite of an immutable object), and changes to it will reflect in any reference to it. What you have in your glob function is a reference to M.

You can look at an np.array as a piece of memory that has many names, and if you changed it, the changes will be evident no matter what name you're using to access it. M[0] is simply a reference to a specific part of this memory. This reflects the object's "state".

If you'd do something like:

M = np.array([1])

def example()
    another_name_for_M = M
    M = 2
    another_name_for_M[0] = 2

you would still see the global M changing, but you're using a new name to access it.

If you would use a string, a tuple, a frozenset and the likes, which are all immutable objects that can not be (easily) changed, you wouldn't be able to actually change their state.

Now to your question, if you don't want the function to mutate the array just send a copy of it using np.copy, and not the actual one:

import numpy as np

my_array = np.array([1])

def array_mutating_function(some_array):
    some_array[0] = 1337
    print some_array # prints [1337]

# send copy to prevent mutating the original array
array_mutating_function(np.copy(my_array))
print my_array # prints [1]

This will effectively make it immutable on the outer scope, since the function will not have a reference to it unless it's using it's name on the outer scope, which is probably not a good idea regardless.

If the function should never change any array, move the copy to be made on inside the function no matter what array is sent, preventing it from changing any array that was sent to it:

def array_mutating_function(some_array):
    some_array = np.copy(some_array)
    some_array[0] = 1337


回答2:

SImply explaining.:

  1. cannot update a global varaible inside a funcion unless access it as global inside function.
  2. But it can modify

Check:

import numpy as np
M = np.array([1])
def loc():
    global M
    M = 2
    return 0
def glob():
    M[0] = 3
    return 0
loc()
print M
>>>2