Python - 为啥通过值传递的 ndarray 在函数外部发生变化? [复制]

Posted

技术标签:

【中文标题】Python - 为啥通过值传递的 ndarray 在函数外部发生变化? [复制]【英文标题】:Python - Why ndarray passed by value changes outside function? [duplicate]Python - 为什么通过值传递的 ndarray 在函数外部发生变化? [复制] 【发布时间】:2017-08-23 05:55:01 【问题描述】:

我有以下功能:

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 时,它在函数范围之外改变了它的值。这怎么可能?

【问题讨论】:

阅读上述副本中的 NumPy 答案。它基本上制作了数组的浅拷贝。尝试使用foo.copy() @rayryeng: [:] 为 Python 列表创建一个浅拷贝。对于 numpy 数组,[:] 不会复制,它只会在数组中创建另一个视图。 @J.F.Sebastian 对。我混淆了我的术语。感谢您的澄清。 @rayryeng:注意:不同之处不仅仅是文字。 Modifying a copy may keep the original list intact but modifying an array view changes the original. 【参考方案1】:

首先,你不会通过传递序列的完整切片来传递“按值”,Python 总是通过赋值,即隐式发生的第一件事是foo = argument 当调用你的函数。

现在回答你的实际问题:

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

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

延伸阅读:http://scipy-cookbook.readthedocs.io/items/ViewsVsCopies.html

【讨论】:

我知道 Python 通过赋值传递。我发现这很有帮助:http://***.com/questions/986006/how-do-i-pass-a-variable-by-reference。我刚刚看到我可以通过复制适用于列表的序列“foo [:]”来隐式传递它。但无论如何你是对的。我将不得不阅读 numpy 文档中的视图。谢谢。【参考方案2】:

在 Python 中,

bar = foo

不制作副本。 barfoo 引用同一个数组对象。

此操作会复制一个列表,但只是一个数组的view

foo[:]

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

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

【讨论】:

我会读到关于 numpy 中的视图。 foo.copy() 解决了这个问题。谢谢。

以上是关于Python - 为啥通过值传递的 ndarray 在函数外部发生变化? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

python:在numpy.ndarray中返回最小值

数据分析2 numpy(ndarray数组,属性,创建,索引切片,运算,函数,随机数), Pandas(Series创建,缺失值处理,特性,索引,DataFrame)

为啥我们不能通过值传递数组来函数?

为啥向量被视为按值传递,即使它是通过 const 引用传递的?

为啥python不允许通过引用传递变量

C:为啥你可以通过值传递(给函数)一个结构,而不是一个数组?