2013-10-25 131 views
6

在numpy的切片我用一些计算numpy的阵列,并发现了一个奇怪的问题,比如,假设我已经进口numpy.arange在IPython中,我运行一些脚本如下:阵列今天

In [5]: foo = arange(10)              

In [8]: foo1 = foo[arange(3)]             

In [11]: foo1[:] = 0               

In [12]: foo 
Out[12]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) 

In [16]: foo2 = foo[0:3]              

In [19]: foo2[:]=0                

In [21]: foo 
Out[21]: array([0, 0, 0, 3, 4, 5, 6, 7, 8, 9]) 

上面显示当我通过foo [arange(3)]切片数组时,我获得了数组切片的副本,但是当我通过foo [0:3]切片数组时,我得到了数组切片的引用,因此foo随foo2而变化。后来我想foo​​和foo2的应该有相同的ID,但似乎并非如此

In [59]: id(foo) 
Out[59]: 27502608 

In [60]: id(foo2) 
Out[60]: 28866880 

In [61]: id(foo[0]) 
Out[61]: 38796768 

In [62]: id(foo2[0]) 
Out[62]: 38813248 

... 

就更奇怪了,如果我继续检查foo和foo2的的ID,他们不是恒定的,有时候,他们做了相互匹配!

In [65]: id(foo2[0]) 
Out[65]: 38928592 

In [66]: id(foo[0])               
Out[66]: 37111504 

In [67]: id(foo[0]) 
Out[67]: 38928592 

任何人都可以解释这一点吗?我真的蟒蛇的这种动态特征混淆

非常感谢

回答

5
foo[arange(3)] 

不是一个切片。 arange(3)的元素用于选择foo的元素来构造一个新的数组。由于这不能有效地返回视图(视图的每个元素必须是独立的引用,并且视图上的操作需要跟随太多的指针),它会返回一个新的数组。

foo[0:3] 

是切片。作为一种观点,这可以高效地完成;它只需要调整一些边界。因此,它返回一个视图。

id(foo[0]) 

foo[0]不是指一个特定的Python对象。为每个数组元素保留单独的Python对象将会非常昂贵,否定了numpy的许多好处。相反,当在numpy ndarray上执行索引操作时,numpy将构造一个新对象以返回。每次你都会得到一个不同ID的对象。

+0

那么,为什么id(foo)也不同于id(foo2)?他们是否使用第一个元素的地址作为他们的地址? – shelper

+1

@shelper:foo不是foo2。尽管它们具有相同的形状,dtype等,虽然它们对于它们的元素使用相同的存储,但它们是不同的对象。我不认为你收到的ID与数组元素的地址有任何关系;它是包含数组元数据的头的地址和指向用于元素的存储的指针。 – user2357112

+1

好吧,我想我明白这个问题,foo和foo2都是很好的包装python对象,id(foo)只是显示python对象的地址,而不是包含数据的内存,实际上可以通过“foo”获取。 __array_interface __ ['data']“ – shelper