python list +空的numpy数组=空的numpy数组?

Giv*_*Alz 6 python arrays numpy numpy-broadcasting

今天,我发现代码中有些奇怪的地方,发现在某些情况下它会执行以下命令:

my_list = [0] + np.array([])
Run Code Online (Sandbox Code Playgroud)

结果my_list如下:

array([], dtype=float64)
Run Code Online (Sandbox Code Playgroud)

一开始我很困惑,比我理解的解释器要先将列表转换为一个numpy数组,然后再尝试广播操作:

>>> np.array([0]) + np.array([])
array([], dtype=float64)
Run Code Online (Sandbox Code Playgroud)

我对此行为有一些疑问:

  • 为什么要广播?
  • python抛出错误会更好吗,至少在这种情况下,列表被转换并消失了?

感谢您的澄清!

And*_*eak 3

首先:

如果 python 抛出错误,至少对于列表被转换并消失的特殊情况,不是更好吗?

我认为这个测试是不可能的。根据这个评论

对于像这样的反向操作b.__radd__(a)我们调用相应的ufunc。

这意味着 using[0] + np.array([])实际上会调用 ufunc np.add([0], np.array([])),它将类似数组的列表转换为数组,而没有机会决定操作数的大小。

所以广播是给定的。(1,)那么问题是拥有形状并(0,)广播到是否明智(0,)。您可以这样想:标量总是广播,并且在大多数情况下,1 元素一维数组与标量一样好:

>>> np.add([0], [])
array([], dtype=float64)

>>> np.add(0, [])
array([], dtype=float64)
Run Code Online (Sandbox Code Playgroud)

如果您以这种方式看待它,那么它通常是有意义的,尽管我同意这令人惊讶,特别是非单长度数组不会像这样广播。但这不是一个错误(只是一个功能的有趣情况)。


更准确地说,广播发生的事情始终是“大小为 1 的维度将广播”。类似数组[0]具有 shape (1,),并且np.array([])具有 shape (与具有 shape 的(0,)标量相反!)。因此广播发生在单例上,结果具有形状。np.int64()()(0,)

如果我们注入更多的单例维度,它会变得更清楚:

>>> ([0] + np.array([])).shape
(0,)

>>> ([[0]] + np.array([])).shape
(1, 0)

>>> ([[[0]]] + np.array([])).shape
(1, 1, 0)

>>> np.shape([[[0]]])
(1, 1, 1)
Run Code Online (Sandbox Code Playgroud)

因此,例如在最后一种情况下,形状(1, 1, 1)将很好地沿其最后一个维度与一维数组一起广播,并且结果确实应该(1, 1, 0)在这种情况下。