从列表中减去数字不引发 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]
中的操作数仍然是 list
和 np.float64
,那么为什么 b - b[-1]
不引发 TypeError
?
编辑:有人回答说list
和np.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)
。
列表实现 mul
和 add
但不实现 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)。
如果我这样做
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]
中的操作数仍然是 list
和 np.float64
,那么为什么 b - b[-1]
不引发 TypeError
?
编辑:有人回答说list
和np.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)
。
列表实现 mul
和 add
但不实现 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)。