从列表中减去数字不引发 TypeError

Substracting number from list not raising TypeError

如果我这样做

a = [1, 2, 7]
a - a[-1]

我明白了TypeError: unsupported operand type(s) for -: 'list' and 'int'

但是,我有一个由 np.float64 组成的列表 b,并且以下代码有效:

type(b)
# list
b - b[-1]
# array([ 281.04209146,    6.57013103,    0.        ])

我认为这是因为 b 中的数字是 np.float64,而 b 有点强制转换为 np.array,然后发生广播。 但我仍然发现这种行为令人惊讶:因为列表中的所有元素不需要具有相同的类型,如果 b[0] 是一个字符串怎么办? b - b[-1] 中的操作数仍然是 listnp.float64,那么为什么 b - b[-1] 不引发 TypeError

编辑:有人回答说listnp.array不一样;好吧,我知道。但是那里 b 不是 np.array。它表现像一个,但它的类型是list,就像我在代码片段中所说的那样。

这是 b 的最小工作示例:

b
# [1598.717274996219, 1324.245314569733, 1317.6751835362861]
type(b[0])
# numpy.float64

当您将 b[0] 设为字符串时,您不会得到相同的 TypeError

b=[np.float_(a_) for a_ in a]

b
Out[4]: [1.0, 2.0, 7.0]

b-b[-1]
Out[5]: array([-6., -5.,  0.])

b[0]='a'

b
Out[7]: ['a', 2.0, 7.0]

b-b[-1]
Traceback (most recent call last):

  File "<#>", line 1, in <module>
    b-b[-1]

TypeError: ufunc 'subtract' did not contain a loop with signature matching types dtype('<U32') dtype('<U32') dtype('<U32')

subtract 中的类型不匹配,你得到一个 TypeError。在原始版本中,当您为 b[-1] 获得 np.float64 时,它会将整个表达式转换为 numpy 数组。所以如果 b[-1] 是一个字符串:

b[2]='a'

b-b[-1]
Traceback (most recent call last):

  File "<#>", line 1, in <module>
    b-b[-1]

TypeError: unsupported operand type(s) for -: 'list' and 'str'

你又回到原来的样子了TypeError

在像 A-B 这样的表达式中,解释器可以将其实现为 A.__sub__(B)B.__rsub__(A)

列表实现 muladd 但不实现 sub

In [29]: [1,2,3]*3
Out[29]: [1, 2, 3, 1, 2, 3, 1, 2, 3]
In [30]: [1,2,3]+[1]
Out[30]: [1, 2, 3, 1]
In [31]: [1,2,3]-3
TypeError: unsupported operand type(s) for -: 'list' and 'int'

np.ndarray 实现 __rsub__

In [32]: [1,2,3]-np.array([1,2,3])
Out[32]: array([0, 0, 0])
# np.array([1,2,3]).__rsub__([1,2,3])

并且该方法试图将 LHS 转换为数组,因此该表达式与:

In [33]: np.asarray([1,2,3]) - np.array([1,2,3])
Out[33]: array([0, 0, 0])

如果列表包含字符串,则失败:

In [35]: ['a',2,3]-np.array([1,2,3])
TypeError: ufunc 'subtract' did not contain a loop with signature matching types dtype('<U11') dtype('<U11') dtype('<U11')

因为该列表变成了字符串数组:

In [36]: np.asarray(['a',2,3])
Out[36]: 
array(['a', '2', '3'], 
      dtype='<U1')

并且未实现字符串 dtype 的数组减法。

如果它是 np.float64,我用数组 RHS 写的所有内容都适用。 np.float64(10) 的行为(在大多数情况下)与 np.array(10.0).

相同

所以所有这些 b 的减法都是相同的:

 b = [np.float64(10), np.float64(1)]
 b - b[-1]
 b - np.float64(1)
 b - np.array(1.0)
 np.array(b) - np.array(1.0)

总之,如果 RHS 是某种数组,它会将 LHS 列表也变成数组。从那里开始,问题是这 2 个数组是否兼容(形状和 dtype)。