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
不复制。 bar
和 foo
引用相同的数组对象。
此操作复制列表,但只是 view
数组:
foo[:]
如果要将 bar
中的更改与 foo
中的更改隔离开来,则需要使用 foo.copy()
。
我建议查看一些基本的 numpy 文档,尤其是关于视图和副本的内容。
首先,您不会通过传递序列的完整片段来传递 "by value",Python 总是通过 assignment,即隐式发生的第一件事是 foo = argument
调用函数时。
现在回答您的实际问题:
创建列表的完整切片会创建一个新列表。您正在将原始列表的浅表副本传递给函数。
创建 numpy 数组的(完整)切片会在原始数组保存的相同数据(内存中的某处)上生成 视图。视图和原始视图共享相同的数据,因为如果您更改一个视图的内容,则更改在所有视图中都是可见的。
进一步阅读:http://scipy-cookbook.readthedocs.io/items/ViewsVsCopies.html
我有以下功能:
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
不复制。 bar
和 foo
引用相同的数组对象。
此操作复制列表,但只是 view
数组:
foo[:]
如果要将 bar
中的更改与 foo
中的更改隔离开来,则需要使用 foo.copy()
。
我建议查看一些基本的 numpy 文档,尤其是关于视图和副本的内容。
首先,您不会通过传递序列的完整片段来传递 "by value",Python 总是通过 assignment,即隐式发生的第一件事是 foo = argument
调用函数时。
现在回答您的实际问题:
创建列表的完整切片会创建一个新列表。您正在将原始列表的浅表副本传递给函数。
创建 numpy 数组的(完整)切片会在原始数组保存的相同数据(内存中的某处)上生成 视图。视图和原始视图共享相同的数据,因为如果您更改一个视图的内容,则更改在所有视图中都是可见的。
进一步阅读:http://scipy-cookbook.readthedocs.io/items/ViewsVsCopies.html