2

我以前看过一两次,但我似乎找不到任何官方文档:Using python rangeobjects as indices in numpy.

import numpy as np
a = np.arange(9).reshape(3,3)
a[range(3), range(2,-1,-1)]
# array([2, 4, 6])

让我们触发一个索引错误,以确认范围不在合法索引方法的官方范围(双关语)内:

a['x']

# Traceback (most recent call last):
#   File "<stdin>", line 1, in <module>
# IndexError: only integers, slices (`:`), ellipsis (`...`), numpy.newaxis (`None`) and integer or boolean arrays are valid indices

现在,numpy 和它的文档之间的细微差异并非完全闻所未闻,也不一定表明该功能不是有意的(例如,请参见此处)。

那么,有人知道为什么这会起作用吗?如果它是一个预期的功能,那么确切的语义是什么/它有什么用?是否有任何 ND 概括?

4

2 回答 2

1

不是一个正确的答案,但评论太长了。

事实上,它似乎适用于任何可索引对象:

import numpy as np

class MyIndex:
    def __init__(self, n):
        self.n = n
    def __getitem__(self, i):
        if i < 0 or i >= self.n:
            raise IndexError
        return i
    def __len__(self):
        return self.n

a = np.array([1, 2, 3])
print(a[MyIndex(2)])
# [1 2]

认为NumPy 代码中的相关行在以下评论中core/src/multiarray/mapping.c

/*
 * Some other type of short sequence - assume we should unpack it like a
 * tuple, and then decide whether that was actually necessary.
 */

但我不完全确定。出于某种原因,如果您删除if i < 0 or i >= self.n: raise IndexError, 即使有 , 也会挂起__len__,因此在某些时候它似乎正在迭代给定对象直到IndexError被提升。

于 2018-11-02T17:52:15.587 回答
1

只是总结一下(感谢评论中的@WarrenWeckesser):实际上记录了这种行为。只需意识到range对象是严格意义上的 python 序列。

所以这只是一个花式索引的例子。但是请注意,它非常慢:

>>> a = np.arange(100000)
>>> timeit(lambda: a[range(100000)], number=1000)
12.969507368048653
>>> timeit(lambda: a[list(range(100000))], number=1000)
7.990526253008284
>>> timeit(lambda: a[np.arange(100000)], number=1000)
0.22483703796751797
于 2018-11-08T23:33:51.823 回答