Python - 为什么按值传递的 ndarray 在函数外发生变化?

Python - Why ndarray passed by value changes outside function?

我有以下功能:

def a_function(foo):
    bar = foo
    print("bar1: ", bar, id(foo))
    bar[0] = foo[2]
    print("bar2: ", bar, id(foo))

以列表作为参数调用:

foo = [0, 1, 2, 3, 4, 5, 6, 7, 8]
print("foo1: ", foo, id(foo))
a_function(foo[:])
print("foo2: ", foo, id(foo))

输出:

foo1:  [0, 1, 2, 3, 4, 5, 6, 7, 8] 140118901565768
bar1:  [0, 1, 2, 3, 4, 5, 6, 7, 8] 140118901566472
bar2:  [2, 1, 2, 3, 4, 5, 6, 7, 8] 140118901566472
foo2:  [0, 1, 2, 3, 4, 5, 6, 7, 8] 140118901565768

以 ndarray 作为参数调用:

foo = np.arange(0,9)
print("foo1: ", foo, id(foo))
a_function(foo[:])
print("foo2: ", foo, id(foo))

输出:

foo1:  [0 1 2 3 4 5 6 7 8] 139814139381760
bar1:  [0 1 2 3 4 5 6 7 8] 139814115258000
bar2:  [2 1 2 3 4 5 6 7 8] 139814115258000
foo2:  [2 1 2 3 4 5 6 7 8] 139814139381760

我将它作为副本传递给 foo[:] 甚至在函数内部再次复制它并且它有自己的 ID。然而,当 foo2 是一个 ndarray 时,它在函数范围之外改变了它的值。这怎么可能?

在Python、

bar = foo

不复制。 barfoo 引用相同的数组对象。

此操作复制列表,但只是 view 数组:

foo[:]

如果要将 bar 中的更改与 foo 中的更改隔离开来,则需要使用 foo.copy()

我建议查看一些基本的 numpy 文档,尤其是关于视图和副本的内容。

首先,您不会通过传递序列的完整片段来传递 "by value",Python 总是通过 assignment,即隐式发生的第一件事是 foo = argument 调用函数时。

现在回答您的实际问题:

创建列表的完整切片会创建一个新列表。您正在将原始列表的浅表副本传递给函数。

创建 numpy 数组的(完整)切片会在原始数组保存的相同数据(内存中的某处)上生成 视图。视图和原始视图共享相同的数据,因为如果您更改一个视图的内容,则更改在所有视图中都是可见的。

进一步阅读:http://scipy-cookbook.readthedocs.io/items/ViewsVsCopies.html