Numpy vs内置副本列表

时间:2016-11-05 14:58:01

标签: python list numpy

以下代码有什么区别

  

内置列表代码

>>> a = [1,2,3,4]
>>> b = a[1:3] 
>>> b[1] = 0
>>> a
[1, 2, 3, 4]
>>> b
[2, 0]
  

numpy array

>>> c = numpy.array([1,2,3,4])
>>> d = c[1:3]
>>> d[1] = 0
>>> c
array([1, 2, 0, 4])
>>> d
array([2, 0])
如在numpy数组c中看到的那样直接实现。我认为在内置列表中,为变量b分配了新内存。可能在numpy中,c [1:3]的引用被指定为d,我不清楚这些。 这如何适用于numpy和内置?

2 个答案:

答案 0 :(得分:3)

要理解的关键点是Python中的每个赋值都将名称与内存中的对象相关联。 Python永远不会复制。现在,了解何时创建新对象以及它们的行为方式变得非常重要。

在第一个示例中,列表中的切片会创建一个新的列表对象。在这种情况下,两个列表都引用了一些相同的对象(int 2和int 3)。复制这些引用的事实就是所谓的“浅”副本。换句话说,复制引用,但它们引用的对象仍然相同。请记住,无论列表中存储的内容类型如何,都是如此。

现在,我们创建一个新对象(int 0)并分配b[1] = 0。由于ab是单独的列表,因此它们现在显示不同的元素不应该让我们感到惊讶。

我喜欢这种情况的pythontutor visualisation

在数组中,"All arrays generated by basic slicing are always views of the original array."

此新对象与原始对象共享数据,并且索引分配的处理方式是对视图的任何更新都将更新共享数据。

答案 1 :(得分:2)

这已被覆盖了很多,但找到一个好的重复是太多的工作。 :(

让我们看看我是否能用你的例子快速描述事物:

>>> a = [1,2,3,4]    # a list contains pointers to numbers elsewhere
>>> b = a[1:3]   # a new list, with copies of those pointers
>>> b[1] = 0    # change one pointer in b
>>> a
[1, 2, 3, 4]    # does not change any pointers in a
>>> b
[2, 0]

array具有不同的结构 - 它有一个带有'原始'数字(或其他字节值)的数据缓冲区。

numpy array
>>> c = numpy.array([1,2,3,4])
>>> d = c[1:3]     # a view; a new array but uses same data buffer
>>> d[1] = 0       # change a value in d; 
>>> c
array([1, 2, 0, 4])   # we see the change in the corrsponding slot of c
>>> d
array([2, 0])

列表的关键点是它们包含指向对象的指针。您可以复制指针而不复制对象;并且您可以在不更改指针的其他副本的情况下更改指针。

为实现numpy的概念而节省内存和速度view。它可以创建一个新数组,而无需复制原始数据 - 因为它可以共享数据缓冲区。但也可以制作副本,例如

 e = c[1:3].copy()
 e[0] = 10
 # no change in c

view v copynumpy中的一个重要主题,也是一个基本主题,特别是在处理不同类型的索引(切片,基本,高级)时。我们可以帮助解决问题,但您也应该阅读numpy文档。没有什么可以替代理解numpy数组存储方式的基础知识。

http://scipy-cookbook.readthedocs.io/items/ViewsVsCopies.html

http://www.scipy-lectures.org/advanced/advanced_numpy/(可能比你现在需要的更先进)