在函数内部访问数组元素时的全局作用域

Global Scope when accessing array element inside function

当我将一个值赋给一个数组时,变量的范围仍然是局部的(参见 loc())。 但是,如果我访问数组的元素,范围将变为全局(请参阅 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]

为什么会这样?如何在不全局修改数组的情况下局部修改数组的元素?我需要在我的函数中有一个循环,一次更改一个元素。

简单解释一下:

  1. 无法更新函数内部的全局变量,除非将其作为全局内部函数访问。
  2. 但是可以修改

检查:

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

你在这里混合了几样东西。

首先,M = 2创建了一个名为M局部变量(你可以在locals()中看到它)并阻止你稍后访问原始 M(虽然你没有这样做......但只是为了说明一点)。这有时被称为 "shadowing".

其次,np.array is a mutable object (the opposite of an immutable object),对它的更改将反映在对它的任何引用中。 glob 函数中的内容是对 M.

的引用

您可以将 np.array 视为具有许多名称的一段内存,如果您更改了它,无论您使用什么名称访问它,更改都会很明显。 M[0] 只是对该内存特定部分的引用。这反映了对象的 "state".

如果你这样做:

M = np.array([1])

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

您仍会看到全局 M 发生变化,但您正在使用新名称访问它。

如果你使用 stringtuplefrozenset 等,它们都是 不可变对象不能(轻易)改变,你将无法真正改变他们的状态。

现在回答你的问题,如果你不希望函数改变数组,只需发送一个 copy of it using np.copy,而不是实际的:

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]

这将有效地使其在外部范围内不可变,因为函数不会引用它,除非它在外部范围内使用它的名称,无论如何这可能不是一个好主意。

如果函数不应该更改任何数组,则无论发送什么数组都将副本移动到函数内部,防止它更改发送给它的任何数组:

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