When Python sees x * y here, what happens:
- if
y is a subclass of x → y.__rmul__(x) , is called
otherwise:
IF x.__mul__(y) returns NotImplemented (which is different from raise NotImplementedError
So there are two ways that __rmul__ can be called - a subclass of ndarray , or ndarray will not be able to multiply with Numeric .
You cannot subclass, and apparently ndarray happy to work with Numeric , therefore .,.
Fortunately, numpy people prepared for such situations - the answer lies in the __array_wrap__ method:
def __array_wrap__(self, out_arr, context=None): return type(self.signal)(out_arr, self.dimensionality)
We use the original signal class along with the original dimension to create a new signal for the new Numeric object.
The whole bit looks like this:
import quantities as pq import numpy as np class Numeric(object): def __init__(self, signal): self.signal = signal self.dimensionality = self.signal.dimensionality self._dimensionality = self.signal._dimensionality def __array__(self): return self.signal def __array_wrap__(self, out_arr, context=None): return type(self.signal)(out_arr, self.dimensionality) def __mul__(self, obj): return self.signal.__mul__(obj) def __rmul__(self, obj): return self.signal.__rmul__(obj) num = Numeric(pq.Quantity([1,2,3], 'mV')) q = pq.Quantity([2,3,4], 'mV') n = np.array([3,4,5]) t = num * num print type(t), t t = num * q print type(t), t t = num * n print type(t), t t = q * num print type(t), t t = n * num print type(t), t
And at startup:
<class 'quantities.quantity.Quantity'> [1 4 9] mV**2 <class 'quantities.quantity.Quantity'> [ 2 6 12] mV**2 <class 'quantities.quantity.Quantity'> [ 3 8 15] mV <class 'quantities.quantity.Quantity'> [ 2 6 12] mV**2 <class 'quantities.quantity.Quantity'> [ 3 8 15] mV