我有以下意外行为
import numpy as np
class Test:
def __radd__(self, other):
print(f'value: {other}')
[1,2,3] + Test()
# prints: value: [1,2,3]
np.array([1,2,3]) + Test()
# prints
# value: 1
# value: 2
# value: 3
我希望第二次添加的行为方式与第一次相同,但事实并非如此。我能看到的唯一逻辑解释是,numpy +
运算符首先以某种方式迭代参数,并尝试将它们中的每一个添加到Test()
,第二个加法(int + Test)
回退到Test.__radd__
所以
a + b
如何在numpy中工作np.add(a, b)
?答案 0 :(得分:4)
这是因为NumPy 'broadcasting'。
您的解释非常正确,因为np.add
可以看到in the docs。
备注强>
就阵列广播而言,相当于x1 + x2。
如果您使用NumPy并查看np.array
与内置列表的不同之处,我发现这更有意义。
Python 3.5.2 (default, Jul 6 2016, 16:37:16)
Type 'copyright', 'credits' or 'license' for more information
IPython 6.2.1 -- An enhanced Interactive Python. Type '?' for help.
In [1]: import numpy as np
In [2]: [1, 2, 3] + [1, 2, 3]
Out[2]: [1, 2, 3, 1, 2, 3]
In [3]: np.array([1, 2, 3]) + np.array([1, 2, 3])
Out[3]: array([2, 4, 6])
查看NDArrayOperatorsMixin
implements the special methods for almost all of Python's builtin operators defined in the `operator` module
的源代码here。看起来__add__, __radd__, __iadd__
都设置为.add
umath函数。 但是我不确定实际的ndarray
是否使用了混合,我认为你必须深入研究C代码以弄清楚它是如何处理的。
答案 1 :(得分:2)
If I expand your class a bit we may get more of an idea of when __add__
is used, and when __radd__
:
class Test:
def __radd__(self, other):
print(f'r value: {other}, {type(other)}')
return f'{other}'
def __add__(self, other):
print(f'a value: {other}, {type(other)}')
return other+3
With a list
In [285]: [1,2,3]+Test()
r value: [1, 2, 3], <class 'list'> # use Test.__radd__
Out[285]: '[1, 2, 3]'
In [286]: Test()+[1,2,3] # tries to use Test.__add__
a value: [1, 2, 3], <class 'list'>
....
<ipython-input-280-cd3f564be47a> in __add__(self, other)
5 def __add__(self, other):
6 print(f'a value: {other}, {type(other)}')
----> 7 return other+3
8
TypeError: can only concatenate list (not "int") to list
With an array:
In [287]: np.arange(3)+Test() # use Test.__radd__ with each array element
r value: 0, <class 'int'>
r value: 1, <class 'int'>
r value: 2, <class 'int'>
Out[287]: array(['0', '1', '2'], dtype=object)
In [288]: Test()+np.arange(3)
a value: [0 1 2], <class 'numpy.ndarray'>
Out[288]: array([3, 4, 5]) # use Test.__add__ on whole array
With itself, a double use of Test.__add__
:
In [289]: Test()+Test()
a value: <__main__.Test object at 0x7fc33a5a7a20>, <class '__main__.Test'>
a value: 3, <class 'int'>
Out[289]: 6
As I commented it can be tricky sorting out the __add__
v __radd__
delegation, and separating that from ndarray
action.
add
with Test()
second gives the same output as [287]:
In [295]: np.add(np.arange(3),Test())
r value: 0, <class 'int'>
r value: 1, <class 'int'>
r value: 2, <class 'int'>
Out[295]: array(['0', '1', '2'], dtype=object)
np.add
with Test()
first is different from [288] above:
In [296]: np.add(Test(),np.arange(3))
a value: 0, <class 'int'>
a value: 1, <class 'int'>
a value: 2, <class 'int'>
Out[296]: array([3, 4, 5], dtype=object)
答案 2 :(得分:1)
你的直觉是正确的。 Numpy添加了每个元素。您也可以使用基元来查看此行为:
np.array([1,2,3]) + 1 # [2,3,4]