Python数组会自动相互复制

Mar*_*erg 5 python numpy

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

a = numpy.zeros(4)
b = a
a[1] = 10
print b[1]
Run Code Online (Sandbox Code Playgroud)

它返回10而不是0.如何断开这两个数组?

Pad*_*ham 2

您需要一份副本:

\n\n
b  = a.copy()\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n
In [5]: a = numpy.zeros(4)    \nIn [6]: b = a   # reference\nIn [7]: id(a)\nOut[7]: 140335847505968    \nIn [8]: id(b)         # same id\'s \nOut[8]: 140335847505968    \nIn [9]: a is b\nOut[9]: True    \nIn [10]: b = a.copy() # new object    \nIn [11]: id(a)\nOut[11]: 140335847505968    \nIn [12]: id(b)   # # now  different id\'s\nOut[12]: 140335437696176    \nIn [13]: a is b # b is no longer pointing to the same memory location\nOut[13]: False\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果使用基本切片对数组进行切片,则 id 将有所不同,但任何更改都将反映在 a 和 b 中,就像使用基本索引时一样。基本 切片生成的所有数组始终是原始数组的视图。视图是一个不拥有其数据的数组,而是引用另一个数组\xe2\x80\x99s 数据。所以视图是一个新对象,但内容仍然属于原始数组。

\n\n

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

\n\n
In [141]: a = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])   \nIn [142]: b = a[1:7:2]    # basic indexing/view\nIn [143]: id(a)\nOut[143]: 140335437385856    \nIn [144]: id(b)      \nOut[144]: 140335437356528    \nIn [145]: b[0] = 999    \nIn [146]: a\nOut[146]: array([  0, 999,   2,   3,   4,   5,   6,   7,   8,   9])\nIn [148]: b\nOut[148]: array([999,   3,   5])    \nIn [149]: a = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])    \nIn [150]: b = a[[0,3,5]]  # advanced indexing/copy  \nIn [151]: b\nOut[151]: array([0, 3, 5])    \nIn [152]: b[0] = 999    \nIn [153]: a\nOut[153]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])    \nIn [154]: b\nOut[154]: array([999,   3,   5])\nIn [157]: a = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])\nIn [158]: b = a[a]   # copy\nIn [159]: b\nOut[159]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])    \nIn [160]: b[0] = 99    \nIn [161]: a\nOut[161]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])    \nIn [162]: b\nOut[162]: array([99,  1,  2,  3,  4,  5,  6,  7,  8,  9])\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n
In [190]: a = [1,2,3,4,5]\n\nIn [191]: b = a[:3]\n\nIn [192]: b[0] = 999\n\nIn [193]: a\nOut[193]: [1, 2, 3, 4, 5]\n\nIn [194]: b\nOut[194]: [999, 2, 3]\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果列表包含子列表并且您创建了一个浅表副本,那么您将遇到 python 列表:

\n\n
In [197]: a = [[1,2,3],[4,5]]\nIn [198]: b = a[:]    \nIn [199]: id(a)\nOut[199]: 140335437468296    \nIn [200]: id(b)\nOut[200]: 140335437417992\nIn [201]: b[0][0] = 999 \nIn [202]: b\nOut[202]: [[999, 2, 3], [4, 5]]   \nIn [203]: a\nOut[203]: [[999, 2, 3], [4, 5]]\n
Run Code Online (Sandbox Code Playgroud)\n\n

您需要制作一份副本。deepcopy:

\n\n
In [204]: a = [[1,2,3],[4,5]]    \nIn [205]: from copy import  deepcopy\nIn [206]: b = deepcopy(a)    \nIn [207]: b[0][0] = 999    \nIn [208]: b\nOut[208]: [[999, 2, 3], [4, 5]]    \nIn [209]: a\nOut[209]: [[1, 2, 3], [4, 5]]\n
Run Code Online (Sandbox Code Playgroud)\n

  • @erb,它也适用于 python2,OP 有一个 numpy 数组而不是列表。 (3认同)