为什么我明确需要 .copy() 一个 numpy array/list?

Why do I explicitly need to .copy() a numpy array/list?

当我想获得一个独立副本时,为什么我必须 .copy() 一个 numpy 数组(或列表,尽管它们没有 .copy() 但可以作为一个很好的最小示例)它,而我不必对变量这样做? 这种行为的原因是什么?

例如设置 a = 1b = a 然后设置 b = 2 不会更改 a,而 a=([0])b = ab[0]=1 也会更改 a.

编辑:

看来这是一个很常见的issue/question,可以通过各种方式问到,所以没找到。对于快速 "I just need to understand what's happening so that I can move on" 我想答案(以及其他 same/similar 问题的答案)已经足够好了。为了更好地理解,我想@chthonicdaemon 在评论中提供的 this link 对我来说似乎是一个很好的起点。

更长的背景

在很多情况下,我必须设置一个带有一些起始值的 numpy 数组,然后在我的程序运行时用其他值填充它。即

logger = np.zeros(5)
#various things happen
logger[0] = 1
#more stuff happens
logger[3] = 1

你明白了。

但通常希望保留基本数组以便能够将结果与其进行比较,所以我只是先设置基本数组,然后从中复制。所以我希望我可以像这样设置它:

base = np.zeros(5)
logger = base
logger[0] = 1

所以

In [1]:base
Out[1]:array([ 0.,  0.,  0.,  0.,  0.])
In [2]:logger
Out[2]:array([ 1.,  0.,  0.,  0.,  0.])

但是对于上面的数组,它们保持 "connected",所以我得到

In [1]:base
Out[1]:array([ 1.,  0.,  0.,  0.,  0.])

我可以通过显式使用

来解决这个问题
logger = base.copy()

但我想知道为什么我必须这样做。

列表(和 numpy 数组)是 可互换的 对象。 str 和 int 不可变的。 不可变对象一旦创建就无法更改,因此:

a = 1
b = a

两者都指向一个int的不可变对象,其值为1。当你改变b时,你给它赋了一个新的值:

b = 3

现在 b 指向不同的对象,而 a 指针没有改变。

现在,列表是可变的。这意味着,您可以在创建这些对象后对其进行更改。

alist = list((1, 2, 3))
newlist = alist

alist == newlist
True

alist 现在是对列表对象的引用。列表对象只是对实际对象的引用的容器。因此,当我为新变量分配 alist 的值时,我只是创建了另一个指向同一容器对象的变量。

操作一个对象会影响两个变量,因为它们引用同一个容器对象。

copy 所做的是制作列表的新副本,包括引用的副本。 (有时称为深拷贝)。这会创建一个新的容器对象,因此在更改其中一个列表时 - 另一个不会更改。