Eric Eric - 5 months ago 31
Python Question

Advanced slicing when passed list instead of tuple in numpy

In the docs, it says (emphasis mine):

non-tuple sequence object
, an ndarray (of data type integer or bool),
and Boolean.


Also recognize that
will trigger advanced indexing, whereas
will trigger basic slicing

I know why
x[(1, 2, slice(None))]
triggers basic slicing. But why does
trigger basic slicing, when
meets the condition of being a non-tuple sequence?

On a related note, why does the following occur?

>>> a = np.eye(4)
>>> a[(1, 2)] # basic indexing, as expected
>>> a[(1, np.array(2))] # basic indexing, as expected

>>> a[[1, 2]] # advanced indexing, as expected
array([[ 0., 1., 0., 0.],
>>> a[[1, np.array(2)]] # basic indexing!!??


There's an exception to that rule. The Advanced Indexing documentation section doesn't mention it, but up above, near the start of the Basic Slicing and Indexing section, you'll see the following text:

In order to remain backward compatible with a common usage in Numeric, basic slicing is also initiated if the selection object is any non-ndarray sequence (such as a list) containing slice objects, the Ellipsis object, or the newaxis object, but not for integer arrays or other embedded sequences.

a[[1, np.array(2)]] doesn't quite trigger basic indexing. It triggers an undocumented part of the backward compatibility logic, as described in a comment in the source code:

     * Sequences < NPY_MAXDIMS with any slice objects
     * or newaxis, Ellipsis or other arrays or sequences
     * embedded, are considered equivalent to an indexing
     * tuple. (`a[[[1,2], [3,4]]] == a[[1,2], [3,4]]`)

The np.array(2) inside the list causes the list to be treated as if it were a tuple, but the result, a[(1, np.array(2))], is still an advanced indexing operation. It ends up applying the 1 and the 2 to separate axes, unlike a[[1, 2]], and the result ends up looking identical to a[1, 2], but if you try it with a 3D a, it produces a copy instead of a view.