Python数组会自动相互复制
我是python的初学者,我不希望这些数组相互复制,但它们是自动复制的:Python数组会自动相互复制,python,numpy,Python,Numpy,我是python的初学者,我不希望这些数组相互复制,但它们是自动复制的: a = numpy.zeros(4) b = a a[1] = 10 print b[1] 它返回10而不是0。如何断开这两个阵列的连接?您需要一个副本: b = a.copy() b=a创建一个引用,因此a是b,它们都指向内存中的同一位置,a.copy()实际上创建了一个新对象 In [5]: a = numpy.zeros(4) In [6]: b = a # reference In [7]: id
a = numpy.zeros(4)
b = a
a[1] = 10
print b[1]
它返回10而不是0。如何断开这两个阵列的连接?您需要一个副本:
b = a.copy()
b=a
创建一个引用,因此a是b
,它们都指向内存中的同一位置,a.copy()
实际上创建了一个新对象
In [5]: a = numpy.zeros(4)
In [6]: b = a # reference
In [7]: id(a)
Out[7]: 140335847505968
In [8]: id(b) # same id's
Out[8]: 140335847505968
In [9]: a is b
Out[9]: True
In [10]: b = a.copy() # new object
In [11]: id(a)
Out[11]: 140335847505968
In [12]: id(b) # # now different id's
Out[12]: 140335437696176
In [13]: a is b # b is no longer pointing to the same memory location
Out[13]: False
如果使用对数组进行切片,则id将有所不同,但任何更改都将反映在a和b中,就像使用基本索引时一样,基本切片生成的所有数组始终是原始数组的视图。是一个数组,它不拥有自己的数据,而是引用另一个数组的数据。因此,视图是一个新对象,但内容仍然属于原始数组
但是,使用高级索引总是返回数据的副本
这是特定的numpy行为,切片常规python平面列表将始终创建一个新列表,其中a中的更改不会反映在b中
In [190]: a = [1,2,3,4,5]
In [191]: b = a[:3]
In [192]: b[0] = 999
In [193]: a
Out[193]: [1, 2, 3, 4, 5]
In [194]: b
Out[194]: [999, 2, 3]
如果python列表包含子列表,并且您创建了一个浅层副本,则会发现python列表:
In [197]: a = [[1,2,3],[4,5]]
In [198]: b = a[:]
In [199]: id(a)
Out[199]: 140335437468296
In [200]: id(b)
Out[200]: 140335437417992
In [201]: b[0][0] = 999
In [202]: b
Out[202]: [[999, 2, 3], [4, 5]]
In [203]: a
Out[203]: [[999, 2, 3], [4, 5]]
您需要做一个:
请记住,Python中的列表是可变的,这意味着在执行赋值操作时,它不会创建它的副本,而是复制引用。这意味着两个变量是相同的列表 例如,您可以执行以下操作:
b=a[:]
创建原始列表的副本
无论如何,我建议您阅读Python.org列表部分以了解更多信息。您可以像这样使用复制模块
from copy import copy
a = numpy.zeros(4)
b = copy(a)
a[1] = 10
print b[1]
这与这样一个事实有关,即当您执行b=a
时,您将a
的引用分配给b
关于这一点的更多信息可以在下面的答案中找到:“数组自动相互复制”是一个错误的陈述,原因有几个。主要原因是您只有一个数组和两个引用该数组的变量名
以下是复制numpy数组的三种方法(即创建与之完全相同的另一个数组):
请注意,切片复制(例如
e=a[:])
将不适用于numpy数组。分配不会创建副本。要理解为什么你的期望是错误的,请看Ned Batchelder。如果你真的想了解Python,那么仔细阅读关于这一点的论述是很重要的。应该注意的是,a.copy()
不是OP使用的有效的Python 2。@erb,它在python2中工作。同样,OP有一个numpy数组而不是列表。有趣的是,尽管id(a)==id(a[:])
的计算结果为False
,切片不会创建副本a[:][3]=4
将变异a
。(您对切片没有这样的说法,但您确实使用了id
来证明它们是相同的。这里有一个案例,id
给出了一个不完整的图片。)这是关于复制的良好通用知识,但是在numpy数组的特定情况下,您可以指望该数组具有copy
方法。无论所分配的值是否不可变,赋值的方式都是相同的。我否决了这个答案,因为它给本来应该更简单的解释增添了不必要的混乱。另外,b=a[:]
更常用于编写b=a[:]
“创建另一个数组,它是第一个数组的深度副本”有点误导:切片操作所做的是创建另一个数组(即,类型为numpy.ndarray
)的新Python对象,它与原始数组共享相同的数据块。没有对数组数据进行复制,无论是深度复制还是其他复制。@MarkDickinson它是一个深度复制。尝试a=numpy.zero(4);b=a[:];a[0]是b[0]
,您将看到它给您的是False,我对这种行为也感到惊讶。这绝对不同于列表。然而,即使它在Python中是一个深度副本,实际上也有两个指向内存中相同地址的不同对象。在赋值中,该地址处的值会被修改,因此可以看到对象之间的变化。这是因为当您拉出a[0]
或b[0]
时,实际上是在装箱数组中保留的未装箱值,并在该点创建一个新的Python对象。尝试a[0]是[0]
,您还会看到False
。然后尝试修改a
:你会看到b
的内容也会改变(反之亦然)。@MarkDickinson啊,有趣的是,“取消装箱”的概念很有意义,a[0]是一个[0]
为假肯定很有趣……我会更新答案以删除假信息。
In [204]: a = [[1,2,3],[4,5]]
In [205]: from copy import deepcopy
In [206]: b = deepcopy(a)
In [207]: b[0][0] = 999
In [208]: b
Out[208]: [[999, 2, 3], [4, 5]]
In [209]: a
Out[209]: [[1, 2, 3], [4, 5]]
from copy import copy
a = numpy.zeros(4)
b = copy(a)
a[1] = 10
print b[1]
>>> a = numpy.zeros(4)
>>> b = a.copy()
>>> c = numpy.copy(a)
>>> d = numpy.array(a)
>>> a[1] = 10
>>> a
array([ 0., 10., 0., 0.])
>>> b
array([ 0., 0., 0., 0.])
>>> c
array([ 0., 0., 0., 0.])
>>> d
array([ 0., 0., 0., 0.])