【问题标题】:Global Scope when accessing array element inside function访问函数内的数组元素时的全局范围
【发布时间】:2015-04-18 10:44:39
【问题描述】:

当我将值分配给数组时,变量的范围仍然是本地的(请参阅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]

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

【问题讨论】:

    标签: python arrays scope


    【解决方案1】:

    你在这里混合了几件事。

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

    其次,np.array 是一个可变 对象(与immutable object 相反),对它的更改将反映在对它的任何引用中。 glob 函数中的内容是对 M 的引用。

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

    如果你想做这样的事情:

    M = np.array([1])
    
    def example()
        another_name_for_M = M
        M = 2
        another_name_for_M[0] = 2
    

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

    如果您使用stringtuplefrozenset 等,它们都是不能(轻松)更改的不可变对象,您不会能够真正改变他们的状态。

    现在回答您的问题,如果您不希望函数改变数组,只需使用 np.copy 发送它的 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
    

    【讨论】:

    • 谢谢!现在更清楚了。所以一个好的经验法则是在任何函数中处理一个数组的副本,例如M1 = M.copy() ...
    【解决方案2】:

    简单解释一下:

    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
    

    【讨论】:

    • loc() 的行为和“全局”的添加是明确的。这个问题与glob() 的行为有关。例如,如果我在 def 中有一个循环该怎么办:for i in range(100): M[i]=i
    • 你可以像这样for i in range(len(M)): M[i]=i 得到M=[0,1,2...]len(N) 全局声明
    • 这并没有什么不同,因为这样你就可以全局更改 M。我想你必须做某事像M1 = M.copy(); for i in range(len(M)): M1[i]=i
    猜你喜欢
    • 2013-06-30
    • 2014-07-13
    • 2017-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多