I am trying to make the following thing work but without success:
I defined my own type Unit
(inherit from build-in type float
) to implement algebra for quantities with units. It does things in the way that:
class Unit(float):
"""provide a simple unit converter for a given quantity"""
def __new__(cls, unit, num=1.):
return super(Unit, cls).__new__(cls, num)
def __init__(self, unit, num=1.):
"""set up base unit"""
self.unit = unit
def __str__(self,):
return '{:s} {:s}'.format(super(Unit, self).__str__(), self.unit)
def __rmul__(self, other):
print 'rmul: {:f}'.format(super(Unit, self).__rmul__(other))
return Unit(self.unit, super(Unit, self).__rmul__(other))
def to(self,target):
fun_conv = _conv(self.unit, target)
return Unit(target, num=fun_conv(self))
c = 3e8 * Unit('m/s') # this will 1) create a Unit instance with magnitude '1' and unit 'm/s',
# 2) invoke __rmul__ to return a new instance with number 3e8 and unit 'm/s' to variable 'c'
print c.to('km/s') # returns 3e5 km/s
However, this __rmul__
is only invoked when float
being the left operand. If I make something like this:
velocities = np.array([20, 10]) * Unit('m/s')
Then Unit.__rmul__
will not be invoked, and the same numpy ndarray
is returned since now Unit('m/s')
was treated like a plain float
with value 1.0
What I expect is: after ndarray * Unit
, a function similar to Unit.to
can be attacted to the instance of ndarray as a method as well as an attribute unit
, so I can further call ndarray.to
to return a copy (or modified version, if it could, for memory efficiency) of the original ndarray that associated with new values and unit. How do I proceed?
According what I have known and searched, __mul__
of the left operand will be of the prior during *
, i.e., the interpretor checks LO.__mul__()
first, if it fails, then goes to RO.__rmul__()
. I don't quite want to override numpy.ndarray.__mul__
because I really don't know how complicated it would be, and whether there would be a big mess in case that it breaks the rules that ndarray acting on other objects.
And, actually I even cannot find where are the codes that defines __mul__
for ndarray
. I simply used inspect.getsource(np.ndarray)
but without success. Why does it fail on this? the exception was barely an IOError
.
Thank you so much for your concern!
If you don't inhereit from float, but instead create a new type wrapping float (so float._ mul_(yourtype) does not work), rmul will do what you want. The wrapping will of course not be free, though... and you'll have to implement all operations you want the type to support.
class T(object):
def __init__(self, val):
self.val = val
def __mul__(self, x):
print("mul")
return T(self.val*x)
def __rmul__(self, x):
print("rmul")
return T(self.val*x)
def __repr__(self):
return str(self.val)
>>> t = T(2)
>>> t * 2
mul
4
>>> 2*t
rmul
4
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With