你有三个问题:
1. 哪个__xx__
方法已重写/定义 numpy 来处理花哨的索引吗?
索引运算符[]
可以使用覆盖__getitem__
, __setitem__
, and __delitem__
。编写一个提供一些内省的简单子类可能很有趣:
>>> class VerboseList(list):
... def __getitem__(self, key):
... print(key)
... return super().__getitem__(key)
...
我们先做一个空的:
>>> l = VerboseList()
现在用一些值填充它。请注意,我们还没有覆盖__setitem__
所以还没有发生任何有趣的事情:
>>> l[:] = range(10)
现在让我们获取一个项目。在索引处0
将0
:
>>> l[0]
0
0
如果我们尝试使用元组,我们会收到错误,但我们首先可以看到元组!
>>> l[0, 4]
(0, 4)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in __getitem__
TypeError: list indices must be integers or slices, not tuple
我们还可以了解Python内部是如何表示切片的:
>>> l[1:3]
slice(1, 3, None)
[1, 2]
您可以用这个对象做更多有趣的事情 - 尝试一下!
2. 为什么Python列表本身不支持花哨的索引?
这很难回答。思考这个问题的一种方式是历史性的:因为numpy
开发人员首先想到了它。
你们这些年轻人。当我还是孩子的时候...
自 1991 年首次公开发布以来,Python 并没有numpy
库,并且要创建多维列表,您必须嵌套列表结构。我认为早期的开发者——尤其是 Guido van Rossum(GvR https://en.wikipedia.org/wiki/Guido_van_Rossum)——最初觉得让事情保持简单是最好的。切片索引已经非常强大了。
然而,不久之后,人们对使用 Python 作为科学计算语言的兴趣与日俱增。 1995 年至 1997 年间,许多开发人员合作开发了一个名为numeric
, 的早期前身numpy
。虽然他不是主要贡献者numeric
or numpy
, GvR 与numeric
开发人员扩展了 Python 的切片语法,使多维数组索引更容易。后来,有一个替代方案numeric
出现称为numarray
; 2006 年,numpy
的创建,结合了两者的最佳功能。
这些库很强大,但它们需要大量的 c 扩展等等。将它们添加到基本的 Python 发行版中会使其变得庞大。尽管 GvR 确实稍微增强了切片语法,但向普通列表添加奇特的索引会极大地改变它们的 API,而且有些多余。考虑到外部库已经可以提供精美的索引,其好处不值得付出代价。
Parts of this narrative are speculative, in all honesty.1 I don't know the developers really! But it's the same decision I would have made. In fact...
确实应该这样。
尽管花式索引非常强大,但我很高兴即使在今天它也不是普通 Python 的一部分,因为这意味着您在使用普通列表时不必费力思考。对于许多任务来说,你并不需要它,而且它带来的认知负担是巨大的。
请记住,我正在谈论施加的负载readers and 维护者。你可能是一个天才,可以在头脑中计算 5 维张量积,但其他人必须阅读你的代码。保留精美的索引numpy
意味着人们不会使用它,除非他们确实需要它,这使得代码总体上更具可读性和可维护性。
3.为什么numpy花式索引在python2上这么慢?是因为我在此版本中没有对 numpy 的原生 BLAS 支持吗?
可能吧。这绝对取决于环境;我在我的机器上没有看到相同的差异。
1. The parts of the narrative that aren't as speculative are drawn from a brief history https://www.computer.org/csdl/mags/cs/2011/02/mcs2011020009.html told in a special issue of Computing in Science and Engineering (2011 vol. 13).