在Python中,您的类的__rmul__
方法是否可以覆盖另一个类的__mul__
方法,而无需更改其他类?
这个问题出现了,因为我正在为某种类型的线性运算符编写一个类,我希望它能够使用乘法语法来增加numpy数组。以下是说明问题的最小示例:
import numpy as np
class AbstractMatrix(object):
def __init__(self):
self.data = np.array([[1, 2],[3, 4]])
def __mul__(self, other):
return np.dot(self.data, other)
def __rmul__(self, other):
return np.dot(other, self.data)
左乘法工作正常:
In[11]: A = AbstractMatrix()
In[12]: B = np.array([[4, 5],[6, 7]])
In[13]: A*B
Out[13]:
array([[16, 19],
[36, 43]])
但右乘法默认为np.ndarray
的版本,它将数组拆分并逐个元素执行乘法(这不是所希望的):
In[14]: B*A
Out[14]:
array([[array([[ 4, 8],
[12, 16]]),
array([[ 5, 10],
[15, 20]])],
[array([[ 6, 12],
[18, 24]]),
array([[ 7, 14],
[21, 28]])]], dtype=object)
在这种情况下,如何在原始(非分裂)数组上调用我自己的类__rmul__
?
欢迎解决numpy数组的特定情况的答案,但我也对覆盖另一个无法修改的第三方类的方法的一般想法感兴趣。
答案 0 :(得分:3)
让NumPy
尊重__rmul__
方法的最简单方法是设置__array_priority__
:
class AbstractMatrix(object):
def __init__(self):
self.data = np.array([[1, 2],[3, 4]])
def __mul__(self, other):
return np.dot(self.data, other)
def __rmul__(self, other):
return np.dot(other, self.data)
__array_priority__ = 10000
A = AbstractMatrix()
B = np.array([[4, 5],[6, 7]])
这就像预期的那样。
>>> B*A
array([[19, 28],
[27, 40]])
问题在于NumPy
并不尊重Pythons "Numeric" Data model。如果numpy数组是第一个参数且numpy.ndarray.__mul__
不可能,那么它会尝试类似:
result = np.empty(B.shape, dtype=object)
for idx, item in np.ndenumerate(B):
result[idx] = A.__rmul__(item)
但是,如果第二个参数的__array_priority__
高于第一个参数,那么真的会使用:
A.__rmul__(B)
但是,自Python 3.5(PEP-465)以来,@
(__matmul__
)运算符可以使用矩阵乘法:
>>> A = np.array([[1, 2],[3, 4]])
>>> B = np.array([[4, 5],[6, 7]])
>>> B @ A
array([[19, 28],
[27, 40]])