从句法上看,这看起来是不一致的,但从语义上看,你在这里做了两件非常不同的事情。在a 和b 的定义中,您正在执行advanced indexing,有时称为fancy indexing,它返回数据的副本。在c 的定义中,您正在执行basic slicing,它返回数据视图。
为了区分,它有助于理解如何将索引传递给 python 对象。下面是一些例子:
>>> class ShowIndex(object):
... def __getitem__(self, index):
... print index
...
>>> ShowIndex()[:,:]
(slice(None, None, None), slice(None, None, None))
>>> ShowIndex()[...,:]
(Ellipsis, slice(None, None, None))
>>> ShowIndex()[0:5:2,::-1]
(slice(0, 5, 2), slice(None, None, -1))
>>> ShowIndex()[0:5:2,np.arange(3)]
(slice(0, 5, 2), array([0, 1, 2]))
>>> ShowIndex()[0:5:2]
slice(0, 5, 2)
>>> ShowIndex()[5, 5]
(5, 5)
>>> ShowIndex()[5]
5
>>> ShowIndex()[np.arange(3)]
[0 1 2]
如您所见,有许多种不同的可能配置。首先,可以传递单个项目,或者可以传递项目的元组。其次,元组可能包含slice 对象、Ellipsis 对象、纯整数或numpy 数组。
基本切片在您传递仅 对象时激活,例如int、slice、或Ellipsis 对象或None(与numpy.newaxis 相同)。这些可以单独传递,也可以在一个元组中传递。以下是文档关于如何激活基本切片的内容:
当 obj 是切片对象(由括号内的 start:stop:step 表示法构造)、整数或切片对象和整数的元组时,就会发生基本切片。 Ellipsis 和 newaxis 对象也可以穿插其中。为了保持向后兼容 Numeric 中的常见用法,如果选择对象是包含切片对象、Ellipsis 对象或 newaxis 对象的任何序列(例如列表),但没有整数数组或其他嵌入序列。
当您传递 numpy 数组、仅包含整数或包含任何类型的子序列的非元组序列或包含数组或子序列的元组时,将激活高级索引。
有关高级索引和基本切片有何不同的详细信息,请参阅文档(链接到上面)。但在这种特殊情况下,我很清楚发生了什么。使用部分索引时,它与以下行为有关:
部分索引的规则是结果的形状(或要在设置中使用的对象的解释形状)是 x 的形状,索引子空间替换为广播索引子空间。如果索引子空间彼此相邻,则广播索引空间直接替换 x 中的所有索引子空间。如果索引子空间是分开的(通过切片对象),那么首先广播的索引空间,然后是 x 的切片子空间。
在使用高级索引的a 的定义中,您有效地将序列[0, 1] 作为元组的第三项传递,并且由于没有发生广播(因为没有其他序列),所以一切都发生为预期的。
在您对b 的定义中,同样使用高级索引,您有效地传递了两个 序列,[0]、第一项(转换为intp 数组)和@ 987654342@,第三项。这两项一起广播,结果与第三项具有相同的形状。然而,由于广播已经发生,我们面临一个问题:我们在新的形状元组中的什么地方插入广播的形状?正如文档所说,
在索引子空间中没有明确的位置,因此它被附加到开头。
因此,广播产生的2 被移动到形状元组的开头,从而产生明显的转置。