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

我是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)
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.])