关于numpy:Python数组会自动相互复制

Python arrays are automatically copying each other

我是Python的初学者,我不希望这些数组相互复制,但它们是自动的:

1
2
3
4
a = numpy.zeros(4)
b = a
a[1] = 10
print b[1]

它返回10而不是0。如何断开这两个阵列的连接?


"数组自动相互复制"是一个错误的语句,原因有几个。主要原因是您只有一个数组,以及引用该数组的两个变量名。

复制numpy数组有三种方法(即创建与之完全相同的另一个数组):

1
2
3
4
5
6
7
8
9
10
11
12
13
>>> 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.])

请注意,切片复制(例如e = a[:])将不适用于numpy数组。


您需要一份副本:

1
b  = a.copy()

b = a创建了一个引用,所以a is b都指向内存中相同的位置,a.copy()实际上创建了一个新对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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中,因为使用基本索引时,由基本切片生成的所有数组始终是原始数组的视图。视图是一个不拥有其数据的数组,而是引用另一个数组的数据。因此视图是一个新对象,但内容仍然属于原始数组。

但是,使用高级索引高级索引始终返回数据的副本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
In [141]: a = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])  
In [142]: b = a[1:7:2]    # basic indexing/view
In [143]: id(a)
Out[143]: 140335437385856    
In [144]: id(b)      
Out[144]: 140335437356528    
In [145]: b[0] = 999    
In [146]: a
Out[146]: array([  0, 999,   2,   3,   4,   5,   6,   7,   8,   9])
In [148]: b
Out[148]: array([999,   3,   5])    
In [149]: a = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])    
In [150]: b = a[[0,3,5]]  # advanced indexing/copy  
In [151]: b
Out[151]: array([0, 3, 5])    
In [152]: b[0] = 999    
In [153]: a
Out[153]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])    
In [154]: b
Out[154]: array([999,   3,   5])
In [157]: a = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
In [158]: b = a[a]   # copy
In [159]: b
Out[159]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])    
In [160]: b[0] = 99    
In [161]: a
Out[161]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])    
In [162]: b
Out[162]: array([99,  1,  2,  3,  4,  5,  6,  7,  8,  9])

这是特定的numpy行为,切片常规的python平面列表将始终创建一个新列表,其中a中的更改不会反映在b中。

1
2
3
4
5
6
7
8
9
10
11
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列表捕获:

1
2
3
4
5
6
7
8
9
10
11
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]]

您需要复制一份.deepcopy:

1
2
3
4
5
6
7
8
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]]


您可以这样使用复制模块

1
2
3
4
5
from copy import copy
a = numpy.zeros(4)
b = copy(a)
a[1] = 10
print b[1]

这与这样一个事实有关:当您执行b = a时,您将a的引用指定给b

有关此问题的更多信息,请参阅以下答案:如何克隆或复制列表?


记住,python中的列表是可变的,这意味着当您执行赋值操作时,它不会创建它的副本,而是复制引用。这意味着两个变量是相同的列表。

您可以这样做,例如:

创建原始列表的副本。

无论如何,我建议您阅读python.org列表部分了解更多信息。