以下代码有什么区别
内置列表代码
>>> 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和内置?
答案 0 :(得分:3)
要理解的关键点是Python中的每个赋值都将名称与内存中的对象相关联。 Python永远不会复制。现在,了解何时创建新对象以及它们的行为方式变得非常重要。
在第一个示例中,列表中的切片会创建一个新的列表对象。在这种情况下,两个列表都引用了一些相同的对象(int
2和int
3)。复制这些引用的事实就是所谓的“浅”副本。换句话说,复制引用,但它们引用的对象仍然相同。请记住,无论列表中存储的内容类型如何,都是如此。
现在,我们创建一个新对象(int
0)并分配b[1] = 0
。由于a
和b
是单独的列表,因此它们现在显示不同的元素不应该让我们感到惊讶。
我喜欢这种情况的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 copy
是numpy
中的一个重要主题,也是一个基本主题,特别是在处理不同类型的索引(切片,基本,高级)时。我们可以帮助解决问题,但您也应该阅读numpy文档。没有什么可以替代理解numpy
数组存储方式的基础知识。
http://scipy-cookbook.readthedocs.io/items/ViewsVsCopies.html
http://www.scipy-lectures.org/advanced/advanced_numpy/(可能比你现在需要的更先进)