【问题标题】:Overriding other __rmul__ with your class's __mul__用你班级的 __mul__ 覆盖其他 __rmul__
【发布时间】:2017-03-08 06:11:49
【问题描述】:

在 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 数组的具体情况,但我也对覆盖另一个无法修改的第三方类的方法的一般想法感兴趣。

【问题讨论】:

  • 为什么不使用@ 运算符?
  • 我相信在通常的 XXX 方法之前检查 rXXX 方法的唯一情况是右侧对象是左侧物体。我对 numpy 内部结构了解得不够多,不知道它们是否可以被子类化。
  • From the docs - These functions are only called if the left operand does not support the corresponding operation and the operands are of different types
  • @FranciscoCouzo 作为从事数值分析的人,@ 运算符看起来很棒! python社区做出了多么棒的决定。我正在使用 Python 2.7.6,但仅此一项可能会让我转到 3.x。

标签: python numpy


【解决方案1】:

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]])

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-01-30
    • 2011-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-27
    • 1970-01-01
    相关资源
    最近更新 更多