Python Numpy中的数组和__rmul__运算符 [英] Array and __rmul__ operator in Python Numpy

查看:173
本文介绍了Python Numpy中的数组和__rmul__运算符的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在一个项目中,我创建了一个类,并且需要在这个新类和一个真实矩阵之间进行操作,因此我像这样重载了__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). 除了,当yx类型的适当子类时,在这种情况下,解释器将首先考虑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.

因此,要回答您的问题,一种解决方法是让foondarray继承,以便应用第二条规则:

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆