Python Numpy中的数组和__rmul__运算符 [英] Array and __rmul__ operator in Python Numpy
问题描述
在一个项目中,我创建了一个类,并且需要在这个新类和一个真实矩阵之间进行操作,因此我像这样重载了__rmul__
函数
In a project, I created a class, and I needed an operation between this new class and a real matrix, so I overloaded the __rmul__
function like this
class foo(object):
aarg = 0
def __init__(self):
self.aarg = 1
def __rmul__(self,A):
print(A)
return 0
def __mul__(self,A):
print(A)
return 0
但是当我打电话时,结果却不是我期望的
but when I called it, the result wasn't what I expected
A = [[i*j for i in np.arange(2) ] for j in np.arange(3)]
A = np.array(A)
R = foo()
C = A * R
输出:
0
0
0
1
0
2
函数似乎被调用了6次,每个元素调用一次.
It seems that the function is called 6 times, once for each elements.
相反,__mul__
功能可以很好地发挥作用
Instead, the __mul__
function works greatly
C = R * A
输出:
[[0 0]
[0 1]
[0 2]]
如果A
不是数组,而只是列表列表,则两者都可以正常工作
If A
isn't an array, but only a list of lists, both work fine
A = [[i*j for i in np.arange(2) ] for j in np.arange(3)]
R = foo()
C = A * R
C = R * A
输出
[[0, 0], [0, 1], [0, 2]]
[[0, 0], [0, 1], [0, 2]]
我真的希望我的__rmul__
函数也能在数组上工作(我原来的乘法函数不是可交换的).我该怎么解决?
I'd really want for my __rmul__
function to work also on arrays (my original multiplication function isn't commutative). How can I solve it?
推荐答案
该行为是预期的.
首先,您必须了解如何真正执行类似x*y
的操作. python解释器将首先尝试计算x.__mul__(y)
.
如果此调用返回NotImplemented
,它将然后尝试计算y.__rmul__(x)
.
除了,当y
是x
类型的适当子类时,在这种情况下,解释器将首先考虑y.__rmul__(x)
,然后再考虑x.__mul__(y)
.
First of all you have to understand how an operation like x*y
is actually executed. The python interpreter will first try to compute x.__mul__(y)
.
If this call returns NotImplemented
it will then try to compute y.__rmul__(x)
.
Except when y
is a proper subclass of the type of x
, in this case the interpreter will first consider y.__rmul__(x)
and then x.__mul__(y)
.
现在发生的是,numpy
根据他是否认为参数是标量或数组来对参数进行不同的处理.
Now what happens is that numpy
treats arguments differently depending on whether or not he thinks the argument are scalar or arrays.
在处理数组时,*
进行逐元素乘法,而标量乘法则将数组的所有条目乘以给定的标量.
When dealing with arrays *
does element-by-element multiplication, while scalar multiplication multiplies all the entry of an array by the given scalar.
在您的情况下,foo()
被numpy视为标量,因此numpy将数组的所有元素乘以foo
.而且,由于numpy不知道foo
类型,因此它返回带有dtype=object
的数组,因此返回的对象是:
In your case foo()
is considered as a scalar by numpy, and thus numpy multiplies all elements of the array by foo
. Moreover, since numpy doesn't know about the type foo
it returns an array with dtype=object
, so the object returned is:
array([[0, 0],
[0, 0],
[0, 0]], dtype=object)
注意:当您尝试计算乘积时,numpy
的数组不会不返回NotImplemented
,因此解释器调用numpy的数组__mul__
方法,该方法执行标量乘法,正如我们所说的那样.此时,numpy会尝试将数组的每个条目乘以您的标量" foo()
,这就是调用__rmul__
方法的位置,因为当数组中的数字__mul__
为NotImplemented
时,数组中的数字将返回NotImplemented
.用foo
参数调用.
Note: numpy
's array does not return NotImplemented
when you try to compute the product, so the interpreter calls numpy's array __mul__
method, which performs scalar multiplication as we said. At this point numpy will try to multiply each entry of the array by your "scalar" foo()
, and here's is where your __rmul__
method gets called, because the numbers in the array return NotImplemented
when their __mul__
is called with a foo
argument.
很明显,如果将参数的顺序更改为初始乘法,则__mul__
方法将立即被调用,并且不会有任何麻烦.
Obviously if you change the order of the arguments to the initial multiplication your __mul__
method gets called immediately and you don't have any trouble.
因此,要回答您的问题,一种解决方法是让foo
从ndarray
继承,以便应用第二条规则:
So, to answer your question, one way to handle this is to have foo
inherit from ndarray
, so that the second rule applies:
class foo(np.ndarray):
def __new__(cls):
# you must implement __new__
# code as before
但是请注意,子类化ndarray
不是简单.
此外,您可能还有其他副作用,因为现在您的课程是ndarray
.
Warning however that subclassing ndarray
isn't straightforward.
Moreover you might have other side effects, since now your class is an ndarray
.
这篇关于Python Numpy中的数组和__rmul__运算符的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!