为什么我明确需要 .copy() 一个 numpy array/list?
Why do I explicitly need to .copy() a numpy array/list?
当我想获得一个独立副本时,为什么我必须 .copy()
一个 numpy 数组(或列表,尽管它们没有 .copy()
但可以作为一个很好的最小示例)它,而我不必对变量这样做? 这种行为的原因是什么?
例如设置 a = 1
和 b = a
然后设置 b = 2
不会更改 a
,而 a=([0])
、b = a
和 b[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 所做的是制作列表的新副本,包括引用的副本。 (有时称为深拷贝)。这会创建一个新的容器对象,因此在更改其中一个列表时 - 另一个不会更改。
当我想获得一个独立副本时,为什么我必须 .copy()
一个 numpy 数组(或列表,尽管它们没有 .copy()
但可以作为一个很好的最小示例)它,而我不必对变量这样做? 这种行为的原因是什么?
例如设置 a = 1
和 b = a
然后设置 b = 2
不会更改 a
,而 a=([0])
、b = a
和 b[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 所做的是制作列表的新副本,包括引用的副本。 (有时称为深拷贝)。这会创建一个新的容器对象,因此在更改其中一个列表时 - 另一个不会更改。