该行为是预期的。
首先你必须了解一个操作是如何进行的x*y
实际上被执行了。 python 解释器将first尝试计算x.__mul__(y)
。
如果此调用返回NotImplemented
它会then尝试计算y.__rmul__(x)
.
Except when y
是该类型的真子类x
,在这种情况下,解释器将首先考虑y.__rmul__(x)
进而x.__mul__(y)
.
现在发生的事情是numpy
根据他认为参数是标量还是数组,以不同的方式对待参数。
处理数组时*
执行逐个元素的乘法,而标量乘法将数组的所有条目乘以给定的标量。
在你的情况下foo()
被 numpy 视为标量,因此 numpy 将数组的所有元素乘以foo
。此外,由于 numpy 不知道类型foo
它返回一个数组dtype=object
,所以返回的对象是:
array([[0, 0],
[0, 0],
[0, 0]], dtype=object)
Note: numpy
的数组确实not return NotImplemented
当您尝试计算乘积时,解释器会调用 numpy 的数组__mul__
方法,正如我们所说,它执行标量乘法。此时 numpy 将尝试将数组的每个条目乘以您的“标量”foo()
,这是你的地方__rmul__
方法被调用,因为数组中的数字返回NotImplemented
当他们的__mul__
被称为foo
争论。
显然,如果您将参数的顺序更改为初始乘法,您的__mul__
方法会立即被调用,您不会遇到任何麻烦。
因此,要回答你的问题,处理这个问题的一种方法是foo
继承自ndarray
,因此第二条规则适用:
class foo(np.ndarray):
def __new__(cls):
# you must implement __new__
# code as before
然而警告说子类化ndarray并不简单。
此外,您可能还会产生其他副作用,因为现在您的班级是ndarray
.