今天,我发现我的代码有些奇怪,发现在某些情况下它会执行以下代码:
my_list = [0] + np.array([])
这导致my_list
为以下内容:
array([], dtype=float64)
一开始我很困惑,比我理解的解释器要先将列表转换成一个numpy数组,然后再尝试广播操作:
>>> np.array([0]) + np.array([])
array([], dtype=float64)
我对此行为有疑问:
感谢您的澄清!
答案 0 :(得分:3)
首先:
如果python抛出错误,至少在这种情况下,列表会转换并消失,这会更好吗?
我认为不可能进行测试。根据{{3}}:
对于像
b.__radd__(a)
这样的反向操作,我们称为相应的ufunc。
这意味着使用[0] + np.array([])
实际上会调用ufunc np.add([0], np.array([]))
,它将类似数组的列表转换为数组,而没有机会决定操作数的大小。
所以广播是必然的。问题是,将形状(1,)
和(0,)
广播到(0,)
是否理智。您可以这样考虑:标量总是广播,在大多数情况下1元素1d数组与标量一样好:
>>> np.add([0], [])
array([], dtype=float64)
>>> np.add(0, [])
array([], dtype=float64)
如果您以这种方式看待它,通常来说还是有道理的,尽管我同意这是令人惊讶的,尤其是非长度数组不会像这样广播。但这不是错误(对于功能而言只是一种有趣的情况)。
更确切地说,广播所发生的总是“尺寸为1的尺寸将广播”。类似于数组的[0]
的形状为(1,)
,np.array([])
的形状为(0,)
(与标量np.int64()
的形状为{{1}相对) }!)。因此广播是在单例上发生的,结果的形状为()
。
如果我们注入更多的单例尺寸,它将变得更加清晰:
(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)
将沿其最后一个维度很好地以1d数组进行广播,在这种情况下,结果的确应该为(1, 1, 1)
。