ndarray 的索引
可以使用标准 Python 语法 x[obj] 对 ndarray 进行索引,其中 x 是数组,obj 是选择对象。根据 obj 的形式,可采用基本索引、高级索引或字段访问。 (ndarrays)
下文多数示例演示如何通过索引引用数组中的数据;同样的索引也适用于数组赋值。具体示例及赋值行为的解释,见“向索引选中的数组赋值”。 (Assigning values to indexed arrays)
注意,在 Python 中,x[(exp1, exp2, ..., expN)] 等价于 x[exp1, exp2, ..., expN],后者只是前者的语法糖。
基本索引
单元素索引
单元素索引与其他标准 Python 序列的索引完全相同:从 0 开始,也接受负数索引,从数组末尾向前计数。
>>> x = np.arange(10)
>>> x[2]
2
>>> x[-2]
8
不必为每个维度的索引分别写一对方括号。
>>> x = x.reshape((2, 5)) # now x is 2-dimensional
>>> x[1, 3]
8
>>> x[1, -1]
9
注意,对多维数组使用少于维数的索引时,会得到一个维数更低的数组。例如:
>>> x[0]
array([0, 1, 2, 3, 4])
也就是说,每个指定的索引会选出由剩余维度构成的数组。上例中,选择 0 后,长度为 5 的剩余维度仍未指定,因此返回的数组保留该维度及其大小。必须注意,返回的数组是视图:它不是原数组的副本,而是指向与原数组相同的内存值。此处返回位置 0 上的一维数组;对这个返回值再使用一个索引,就会得到单个元素: (view)
>>> x[0][2]
2
因此 x[0, 2] == x[0][2]。不过,第二种写法效率较低,因为第一次索引后会创建临时数组,再对它使用索引 2。
切片与步长
基本切片把 Python 的切片概念扩展到 N 个维度。当 obj 是切片对象、整数,或由切片对象与整数组成的元组时,就会采用基本切片。切片对象可在方括号内用 start:stop:step 构造,也可以在这些对象之间插入 Ellipsis 和 newaxis。 (slice)
最简单的情况是用 N 个整数索引一个 N 维数组,返回表示对应条目的数组标量。与 Python 一样,所有索引从零开始:第 i 个索引 nᵢ 的有效范围是 0 ≤ nᵢ < dᵢ,其中 dᵢ 是数组形状的第 i 个分量。负索引表示从数组末尾开始计数,即 nᵢ < 0 时将其解释为 nᵢ + dᵢ。 (array
scalar)
基本切片生成的所有数组始终都是原数组的视图。 (views)
序列切片的标准规则分别适用于基本切片的每个维度,包括步长。需要记住以下概念:
-
基本切片语法为
i:j:k,其中 i 是起始索引,j 是终止索引,k 是步长且 k ≠ 0。它在相应维度选择 m 个元素,索引依次为 i、i + k、…、i + (m − 1)k。其中 m = q + (r ≠ 0),q 和 r 分别是 (j − i) 除以 k 所得的商和余数,即 j − i = qk + r。原文将正向终止条件写作 i + (m − 1)k < j;负步长则按下面的反向切片规则处理。例如:>>> x = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) >>> x[1:7:2] array([1, 3, 5]) -
负数 i 和 j 分别解释为 n + i 和 n + j,其中 n 是对应维度的元素数。负数 k 表示朝较小索引方向移动。沿用上例:
>>> x[-2:10] array([8, 9]) >>> x[-3:3:-1] array([7, 6, 5, 4]) -
设 n 为被切片维度的元素数。省略 i 时,若 k > 0,默认 i = 0;若 k < 0,默认 i = n − 1。省略 j 时,若 k > 0,默认 j = n;若 k < 0,默认边界为 −n − 1。省略 k 时默认步长为 1。
::与:相同,表示选择该轴上的全部索引。沿用上例:>>> x[5:] array([5, 6, 7, 8, 9]) -
如果选择元组中的对象数少于 N,则后续维度默认使用
:。例如:>>> x = np.array([[[1],[2],[3]], [[4],[5],[6]]]) >>> x.shape (2, 3, 1) >>> x[1:2] array([[[4], [5], [6]]]) -
整数 i 与切片
i:i+1选择相同的值,但前者使返回对象的维数减少 1。特别是,若选择元组第 p 项为整数、其余项均为:,会返回对应的 N − 1 维子数组。若 N = 1,则返回数组标量;这类对象详见“标量”。 (Scalars) -
如果选择元组除了第 p 项是切片
i:j:k,其余项均为:,返回数组仍有 N 个维度。它相当于沿第 p 轴,堆叠分别用整数索引 i、i+k、…、i+(m−1)k 选出的子数组;正向切片中末项小于 j。 -
基本切片的元组若有多个非
:项,相当于依次应用每个非:项、同时把其他非:项换为:。因此,在基本切片中,x[ind1, …, ind2,:] 的作用类似x[ind1][..., ind2, :]。 -
可以通过切片给数组赋值,但与列表不同,不能借此增大数组。
x[obj] = value中的 value 必须具有与x[obj]相同的形状,或者能广播到该形状。 -
可以先构造切片元组 obj,再使用
x[obj]。构造时可用 slice 对象替代方括号中的 start:stop:step。例如,x[1:10:5, ::-1]也可写为obj = (slice(1, 10, 5), slice(None, None, -1)); x[obj]。这适合编写处理任意维数数组的通用代码,详情见“在程序中处理可变数量的索引”。 (Dealing with variable numbers of indices within programs)
维度索引工具
有些工具可以帮助在表达式和赋值中轻松匹配数组形状。
Ellipsis 会展开为足够数量的 :,使选择元组覆盖全部维度。多数情况下,展开后的选择元组长度为 x.ndim。索引中最多只能有一个省略号。沿用上例:
>>> x[..., 0]
array([[1, 2, 3],
[4, 5, 6]])
它等价于:
>>> x[:, :, 0]
array([[1, 2, 3],
[4, 5, 6]])
选择元组中的每个 newaxis 都会在结果中新增一个长度为 1 的维度,插入位置就是 newaxis 在元组中的位置。newaxis 是 None 的别名,换成 None 结果相同。沿用上例:
>>> x[:, np.newaxis, :, :].shape
(2, 1, 3, 1)
>>> x[:, None, :, :].shape
(2, 1, 3, 1)
当组合两个数组本来需要显式改变形状时,这个功能很方便。例如:
>>> x = np.arange(5)
>>> x[:, np.newaxis] + x[np.newaxis, :]
array([[0, 1, 2, 3, 4],
[1, 2, 3, 4, 5],
[2, 3, 4, 5, 6],
[3, 4, 5, 6, 7],
[4, 5, 6, 7, 8]])
高级索引
选择对象 obj 是非元组序列、整数或布尔类型的 ndarray,或者包含至少一个序列对象或整数/布尔 ndarray 的元组时,会触发高级索引。高级索引分为整数索引和布尔索引两类。
高级索引始终返回数据副本,与返回视图的基本切片不同。 (view)
整数数组索引
整数数组索引可以根据元素的 N 维索引,选取数组中的任意条目。每个整数数组提供相应维度上的一组索引。
索引数组允许包含负值,其行为与单个索引或切片中的负值相同:
>>> x = np.arange(10, 1, -1)
>>> x
array([10, 9, 8, 7, 6, 5, 4, 3, 2])
>>> x[np.array([3, 3, 1, 8])]
array([7, 7, 9, 2])
>>> x[np.array([3, 3, -3, 8])]
array([7, 7, 4, 2])
如果索引越界,就会抛出 IndexError:
>>> x = np.array([[1, 2], [3, 4], [5, 6]])
>>> x[np.array([1, -1])]
array([[3, 4],
[5, 6]])
>>> x[np.array([3, 4])]
Traceback (most recent call last):
...
IndexError: index 3 is out of bounds for axis 0 with size 3
当整数索引数组的个数恰好等于被索引数组的维数时,索引行为比较直接,但与切片不同。
所有高级索引总会先广播,再作为一个整体迭代: (broadcast)
result[i_1, ..., i_M] == x[ind_1[i_1, ..., i_M], ind_2[i_1, ..., i_M],
..., ind_N[i_1, ..., i_M]]
结果形状与广播后的索引数组 ind_1、…、ind_N 的形状相同。如果索引无法广播到相同形状,就会抛出 IndexError: shape mismatch: indexing arrays could not be broadcast together with shapes… 异常。
多维索引数组的用法相对少见,但它是允许的,并且对某些问题很有帮助。先看最简单的多维情况:
>>> y = np.arange(35).reshape(5, 7)
>>> y
array([[ 0, 1, 2, 3, 4, 5, 6],
[ 7, 8, 9, 10, 11, 12, 13],
[14, 15, 16, 17, 18, 19, 20],
[21, 22, 23, 24, 25, 26, 27],
[28, 29, 30, 31, 32, 33, 34]])
>>> y[np.array([0, 2, 4]), np.array([0, 1, 2])]
array([ 0, 15, 30])
这里的索引数组形状一致,并且被索引数组的每个维度都有一个对应索引数组,因此结果与索引数组具有相同形状;结果中每个位置的值,由所有索引数组在该位置的值共同确定。本例中,两个索引数组的第一个值都是 0,所以结果的首项是 y[0, 0];下一项是 y[2, 1],最后一项是 y[4, 2]。
如果索引数组形状不同,NumPy 会尝试把它们广播到相同形状;如果无法广播,就抛出异常:
>>> y[np.array([0, 2, 4]), np.array([0, 1])]
Traceback (most recent call last):
...
IndexError: shape mismatch: indexing arrays could not be broadcast
together with shapes (3,) (2,)
广播机制允许把索引数组与其他维度的标量索引组合使用。效果是:标量值会用于索引数组对应的所有位置。
>>> y[np.array([0, 2, 4]), 1]
array([ 1, 15, 29])
更复杂一点,可以只用索引数组指定原数组的部分维度。这种情况需要仔细理解。例如,对 y 只使用一个索引数组:
>>> y[np.array([0, 2, 4])]
array([[ 0, 1, 2, 3, 4, 5, 6],
[14, 15, 16, 17, 18, 19, 20],
[28, 29, 30, 31, 32, 33, 34]])
这会构造一个新数组:索引数组的每个值从原数组选出一行,结果形状为(索引元素数量,行长度)。
通常,结果形状是索引数组形状(或所有索引数组广播后的共同形状),与被索引数组中未使用、即尚未索引的各维度形状的拼接。
示例
要从每行选取一个指定元素,行索引为 [0, 1, 2],列索引给出对应行中要选的元素,此处为 [0, 1, 0]。组合两者即可用高级索引完成:
>>> x = np.array([[1, 2], [3, 4], [5, 6]])
>>> x[[0, 1, 2], [0, 1, 0]]
array([1, 4, 5])
可以借助广播,实现类似前面基本切片的行为。ix_ 函数可以辅助这种广播,结合示例最容易理解。
示例
要用高级索引从一个 4×3 数组中选出角点,就要选择列属于 [0, 2]、行属于 [0, 3] 的全部元素。高级索引需要明确指定每个元素;按前面的方法可以写成:
>>> x = np.array([[ 0, 1, 2],
... [ 3, 4, 5],
... [ 6, 7, 8],
... [ 9, 10, 11]])
>>> rows = np.array([[0, 0],
... [3, 3]], dtype=np.intp)
>>> columns = np.array([[0, 2],
... [0, 2]], dtype=np.intp)
>>> x[rows, columns]
array([[ 0, 2],
[ 9, 11]])
不过,上面的索引数组只是重复自身,因此可以用广播简化,类似于 rows[:, np.newaxis] + columns 这样的操作:
>>> rows = np.array([0, 3], dtype=np.intp)
>>> columns = np.array([0, 2], dtype=np.intp)
>>> rows[:, np.newaxis]
array([[0],
[3]])
>>> x[rows[:, np.newaxis], columns]
array([[ 0, 2],
[ 9, 11]])
也可以用 ix_ 函数完成这种广播:
>>> x[np.ix_(rows, columns)]
array([[ 0, 2],
[ 9, 11]])
注意,不调用 np.ix_ 时,只会选中对角位置的元素:
>>> x[rows, columns]
array([ 0, 11])
这是使用多个高级索引时最需要记住的区别。
示例
高级索引的一种实际用途是颜色查找表:把图像中的值映射为 RGB 三元组以供显示。查找表形状可以为 (nlookup, 3)。使用形状为 (ny, nx)、dtype=np.uint8 的图像对该表索引,会得到形状为 (ny, nx, 3) 的数组,使每个像素位置都对应一个 RGB 三元组。也可使用其他整数类型,只要索引值没有超出查找表范围。
布尔数组索引
当 obj 是布尔类型的数组对象时,例如比较运算符的返回值,就会采用这类高级索引。单个布尔索引数组实际上近似等价于 x[obj.nonzero()]:如前文所述,obj.nonzero() 返回长度为 obj.ndim 的整数索引数组元组,表示 obj 中值为 True 的位置。不过,在 obj.shape == x.shape 时,直接使用布尔数组更快。
如果 obj.ndim == x.ndim,x[obj] 返回一维数组,包含 x 中对应 obj 为 True 的元素;查找顺序为按行优先的 C 顺序。如果 obj 的形状与 x 的相应维度不匹配,就会产生索引错误,不论其中的布尔值是 True 还是 False。 (row-major)
常见用途是筛选符合要求的元素值。例如,选出数组中所有不是 numpy.nan 的条目:
>>> x = np.array([[1., 2.], [np.nan, 3.], [np.nan, np.nan]])
>>> x[~np.isnan(x)]
array([1., 2., 3.])
或者,给所有负值元素加上一个常量:
>>> x = np.array([1., -1., -2., 3])
>>> x[x < 0] += 20
>>> x
array([ 1., 19., 18., 3.])
通常,索引中包含布尔数组时,其结果与在相同位置插入 obj.nonzero()、再使用整数数组索引机制相同。x[ind_1, boolean_array, ind_2] 等价于 x[(ind_1,) + boolean_array.nonzero() + (ind_2,)]。
如果只有一个布尔数组、没有整数索引数组,行为比较直接;只需确保布尔索引的维数与它要作用的维数完全一致。
通常,布尔数组的维数少于被索引数组时,等价于 x[b, ...]:在 b 之后补足所需数量的 :,以覆盖 x 的全部维度。因此,结果的第一维长度为布尔数组中 True 的数量,后面接上被索引数组剩余的维度:
>>> x = np.arange(35).reshape(5, 7)
>>> b = x > 20
>>> b[:, 5]
array([False, False, False, True, True])
>>> x[b[:, 5]]
array([[21, 22, 23, 24, 25, 26, 27],
[28, 29, 30, 31, 32, 33, 34]])
这里从原数组选出第 4 行和第 5 行,并组合成一个二维数组。
示例
从数组中选出所有元素之和小于或等于 2 的行:
>>> x = np.array([[0, 1], [1, 1], [2, 2]])
>>> rowsum = x.sum(-1)
>>> x[rowsum <= 2, :]
array([[0, 1],
[1, 1]])
组合多个布尔索引数组,或者组合布尔数组与整数索引数组时,用 obj.nonzero() 的等价关系最容易理解。ix_ 也支持布尔数组,行为符合预期。
示例
使用布尔索引选出行内元素之和为偶数的行,同时用高级整数索引选出第 0 列和第 2 列。借助 ix_ 可写为:
>>> x = np.array([[ 0, 1, 2],
... [ 3, 4, 5],
... [ 6, 7, 8],
... [ 9, 10, 11]])
>>> rows = (x.sum(-1) % 2) == 0
>>> rows
array([False, True, False, True])
>>> columns = [0, 2]
>>> x[np.ix_(rows, columns)]
array([[ 3, 5],
[ 9, 11]])
不调用 np.ix_ 时,只会选中对角位置的元素。
也可以不用 np.ix_,对照前面的整数数组示例:
>>> rows = rows.nonzero()[0]
>>> x[rows[:, np.newaxis], columns]
array([[ 3, 5],
[ 9, 11]])
示例
用一个形状为 (2, 3)、包含 4 个 True 的二维布尔数组,从形状为 (2, 3, 5) 的三维数组选取行,会得到形状为 (4, 5) 的二维结果:
>>> x = np.arange(30).reshape(2, 3, 5)
>>> x
array([[[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14]],
[[15, 16, 17, 18, 19],
[20, 21, 22, 23, 24],
[25, 26, 27, 28, 29]]])
>>> b = np.array([[True, True, False], [False, True, True]])
>>> x[b]
array([[ 0, 1, 2, 3, 4],
[ 5, 6, 7, 8, 9],
[20, 21, 22, 23, 24],
[25, 26, 27, 28, 29]])
组合高级索引与基本索引
当索引中至少有一个切片 :、省略号 ... 或 newaxis,或者数组的维数大于高级索引个数时,行为会更加复杂。可以把它理解为将每个高级索引元素对应的索引结果拼接起来。
最简单的情况是单个高级索引与切片组合。例如:
>>> y = np.arange(35).reshape(5,7)
>>> y[np.array([0, 2, 4]), 1:3]
array([[ 1, 2],
[15, 16],
[29, 30]])
实际上,切片与索引数组操作彼此独立:切片先选取索引 1 和 2 的列,即第 2、3 列;然后索引数组选取索引 0、2、4 的行,即第 1、3、5 行。这等价于:
>>> y[:, 1:3][np.array([0, 2, 4]), :]
array([[ 1, 2],
[15, 16],
[29, 30]])
例如,单个高级索引可以替代切片,得到相同数值的结果数组。不过,这个结果是副本,内存布局也可能不同。能使用切片时,优先使用切片。例如:
>>> x = np.array([[ 0, 1, 2],
... [ 3, 4, 5],
... [ 6, 7, 8],
... [ 9, 10, 11]])
>>> x[1:2, 1:3]
array([[4, 5]])
>>> x[1:2, [1, 2]]
array([[4, 5]])
理解多个高级索引组合的最简单方法,可能是从结果形状出发。索引操作包含两部分:由基本索引(不包括整数)定义的子空间,以及高级索引部分定义的子空间。需要区分以下两种情况:
-
全部高级索引相邻,例如
x[..., arr1, arr2, :];但x[arr1, :, 1]不属于这种情况,因为在这里整数1也算作高级索引的一部分。
第一种情况下,高级索引操作产生的维度排在结果最前面,其后才是基本索引子空间的维度。第二种情况下,高级索引产生的维度插入到它们在原数组中对应的位置。后一种逻辑使简单高级索引的表现与切片相似。
示例
假设 x.shape 为 (10, 20, 30),ind 是形状为 (2, 5, 2) 的 intp 索引数组,则 result = x[..., ind, :] 的形状为 (10, 2, 5, 2, 30),因为形状 (20,) 的子空间被形状 (2, 5, 2) 的广播索引子空间替代。若 i、j、k 遍历这个 (2, 5, 2) 子空间,就有 result[..., i, j, k, :] = x[..., ind[i, j, k], :]。此例与 x.take(ind, axis=-2) 的结果相同。
示例
设 x.shape 为 (10, 20, 30, 40, 50),ind_1 与 ind_2 可广播到形状 (2, 3, 4)。那么 x[:, ind_1, ind_2] 的形状为 (10, 2, 3, 4, 40, 50),因为原来形状为 (20, 30) 的子空间被索引形成的 (2, 3, 4) 子空间替代。但是,x[:, ind_1, :, ind_2] 的形状为 (2, 3, 4, 10, 30, 50):索引子空间没有一个明确无歧义的插入位置,所以被放到最前面。始终可以用 .transpose() 把这个子空间移到需要的位置。注意,此例无法用 take 复现。
示例
切片可以与经过广播的布尔索引组合:
>>> x = np.arange(35).reshape(5, 7)
>>> b = x > 20
>>> b
array([[False, False, False, False, False, False, False],
[False, False, False, False, False, False, False],
[False, False, False, False, False, False, False],
[ True, True, True, True, True, True, True],
[ True, True, True, True, True, True, True]])
>>> x[b[:, 5], 1:3]
array([[22, 23],
[29, 30]])
字段访问
如果 ndarray 对象是结构化数组,就可以像字典一样,用字符串索引访问数组字段。 (fields)
x['field-name'] 返回数组的新视图,形状与 x 相同(字段本身是子数组时除外),数据类型为 x.dtype['field-name'],只包含指定字段的数据。记录数组的标量也能用这种方式进行索引。 (view) (record array)
还可以用字段名列表索引结构化数组,例如 x[['field-name1', 'field-name2']]。从 NumPy 1.16 开始,这种操作返回只包含所选字段的视图;旧版本返回副本。多字段索引的详情见用户指南的“结构化数组”。 (Structured arrays)
如果访问的字段是子数组,该子数组的各个维度会追加到结果形状末尾。例如:
>>> x = np.zeros((2, 2), dtype=[('a', np.int32), ('b', np.float64, (3, 3))])
>>> x['a'].shape
(2, 2)
>>> x['a'].dtype
dtype('int32')
>>> x['b'].shape
(2, 2, 3, 3)
>>> x['b'].dtype
dtype('float64')
扁平迭代器索引
x.flat 返回遍历整个数组的迭代器,使用 C 连续顺序,即最后一个索引变化最快。只要选择对象不是元组,就可以对这个迭代器使用基本切片或高级索引;从 x.flat 是一维视图这一点就能理解。它可以使用一维、C 顺序展平索引进行整数索引,因此返回数组的形状就是整数索引对象的形状。
向索引选中的数组赋值
如前所述,可以用单个索引、切片、索引数组和掩码数组选出数组子集并赋值。赋入的值必须形状兼容,即与索引结果形状相同,或能广播到该形状。例如,可以将常量赋给切片:
>>> x = np.arange(10)
>>> x[2:7] = 1
也可以赋入大小合适的数组:
>>> x[2:7] = np.arange(5)
注意,将较高精度或更宽泛类型赋给较低类型时,值可能改变,例如浮点数转整数;某些转换还会抛出异常,例如将复数赋给浮点数或整数数组:
>>> x[1] = 1.2
>>> x[1]
1
>>> x[1] = 1.2j
Traceback (most recent call last):
...
TypeError: can't convert complex to int
与某些读取操作(例如数组索引和掩码索引)不同,赋值始终作用于原数组的数据;否则也不符合赋值的意义。不过,有些操作可能与直觉不同。下面这个例子经常令人意外:
>>> x = np.arange(0, 50, 10)
>>> x
array([ 0, 10, 20, 30, 40])
>>> x[np.array([1, 1, 3, 1])] += 1
>>> x
array([ 0, 11, 20, 31, 40])
人们往往以为索引 1 处的值会增加 3,实际上它只增加 1。原因是:先从原数组取出索引 1、1、3、1 处的值形成临时数组,再给临时数组加 1,最后将它写回原数组。因此,x[1] + 1 这个值被写入 x[1] 三次,而不是把 x[1] 连续递增三次。
在程序中处理可变数量的索引
索引语法非常强大,但直接处理可变数量的索引时有一定限制。例如,要编写能处理不同维数参数的函数,又不为每种可能维数编写特例,该怎么办?把元组用作索引时,元组会被解释为一组索引。例如:
>>> z = np.arange(81).reshape(3, 3, 3, 3)
>>> indices = (1, 1, 1, 1)
>>> z[indices]
40
因此,可以在代码中构造包含任意数量索引的元组,再把它用于索引操作。
程序中可以用 Python 的 slice() 函数指定切片。例如:
>>> indices = (1, 1, 1, slice(0, 2)) # same as [1, 1, 1, 0:2]
>>> z[indices]
array([39, 40])
同样,可以在代码中使用 Ellipsis 对象指定省略号:
>>> indices = (1, Ellipsis, 1) # same as [1, ..., 1]
>>> z[indices]
array([[28, 31, 34],
[37, 40, 43],
[46, 49, 52]])
因此,np.nonzero() 的输出可以直接用作索引,因为它始终返回索引数组组成的元组。
由于元组具有这种特殊含义,它不会像列表一样自动转换为数组。例如:
>>> z[[1, 1, 1, 1]] # produces a large array
array([[[[27, 28, 29],
[30, 31, 32], ...
>>> z[(1, 1, 1, 1)] # returns a single value
40
详细说明
下面是一些日常索引中通常不太重要的细节,排列不分先后:
-
NumPy 原生索引类型为
intp,可能不同于默认整数数组类型。intp是能够安全索引任意数组的最小数据类型;对高级索引而言,它可能比其他类型更快。 -
高级索引赋值一般不保证迭代顺序。因此,同一元素被赋值多次时,无法预测最终结果。
-
空元组索引是零维数组的完整标量索引:如果
x是零维数组,x[()]返回标量,否则返回视图。另一方面,x[...]始终返回视图。 -
如果索引中有零维数组,并且构成完整的整数索引,结果将是标量而不是零维数组;此时不会触发高级索引。
-
如果索引中有省略号
...,但它的展开长度为零,即不替代任何:,结果仍然一定是数组。没有高级索引时返回视图,有高级索引时返回副本。 -
布尔数组与
nonzero的等价关系不适用于零维布尔数组。 -
如果高级索引结果不含元素,但其中某个单独索引越界,是否抛出
IndexError是未定义的。例如x[[], [123]],其中123越界。 -
如果赋值时发生类型转换错误,例如用字符串序列更新数值数组,目标数组可能处于无法预测的部分更新状态。但若出现的是其他错误,例如索引越界,数组将保持不变。
-
高级索引结果的内存布局会针对每次索引操作进行优化,不能假定采用特定的内存顺序。
-
使用子类时,尤其是会改变形状的子类,默认
ndarray.__setitem__行为会在基本索引时调用__getitem__,但在高级索引时不会。对于这类子类,更合适的方式可能是先取得底层数据的基类 ndarray 视图,再调用ndarray.__setitem__;如果子类的__getitem__不返回视图,就必须这样做。











暂无评论内容