python 列表 + 空 numpy 数组 = 空 numpy 数组?

python list + empty numpy array = empty numpy array?

今天我注意到我的代码有些奇怪,并发现在某些情况下它 运行 归结为执行以下内容:

my_list = [0] + np.array([])

这导致 my_list 如下:

array([], dtype=float64)

一开始我很困惑,后来我了解到解释器首先将列表转换为 numpy 数组,然后尝试进行广播操作:

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

我对此行为有一些疑问:

感谢您的澄清!

首先:

Wouldn't it be better if python threw an error, at least for this particular case where a list is converted and made disappear?

我不认为测试是可能的。根据to this comment:

For reversed operations like b.__radd__(a) we call the corresponding ufunc.

这意味着使用 [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)

如果你这样看,它通常是有道理的,尽管我同意这很令人惊讶,尤其是非等长数组不会像这样广播。但这不是一个错误(只是一个功能的有趣情况)。


更准确地说,广播发生的事情总是"dimensions with size 1 will broadcast"。类数组 [0] 的形状为 (1,),而 np.array([]) 的形状为 (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)

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