Overriding other __rmul__ with your class's __mul__

匿名 (未验证) 提交于 2019-12-03 08:52:47

问题:

In Python, is it possible for your class's __rmul__ method to override another class's __mul__ method, without making changes to the other class?

This question arises since I'm writing a class for a certain type of linear operator, and I want it to be able to multiply numpy arrays using the multiplication syntax. Here is a minimal example illustrating the issue:

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) 

Left multiplication works fine:

In[11]: A = AbstractMatrix() In[12]: B = np.array([[4, 5],[6, 7]]) In[13]: A*B Out[13]:  array([[16, 19],        [36, 43]]) 

But right multiplication defaults to np.ndarray's version, which splits the array up and performs multiplication element-by-element (this not what is desired):

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) 

In this situation, how can I make it call my own class's __rmul__ on the original (unsplit) array?

Answers addressing the specific case of numpy arrays are welcome but I am also interested in the general idea of overriding methods of another third party class that cannot be modified.

回答1:

The easiest way to make NumPy respect your __rmul__ method is to set an __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]]) 

This works like expected.

>>> B*A array([[19, 28],        [27, 40]]) 

The problem is that NumPy doesn't respect Pythons "Numeric" Data model. If a numpy array is the first argument and numpy.ndarray.__mul__ isn't possible then it tries something like:

result = np.empty(B.shape, dtype=object) for idx, item in np.ndenumerate(B):     result[idx] = A.__rmul__(item) 

However if the second argument has an __array_priority__ and it's higher than the one of the first argument only then it really uses:

A.__rmul__(B) 

However since Python 3.5 (PEP-465) there is the @ (__matmul__) operator that can utilize matrix multiplication:

>>> A = np.array([[1, 2],[3, 4]]) >>> B = np.array([[4, 5],[6, 7]]) >>> B @ A array([[19, 28],        [27, 40]]) 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!