trzemecki / Unum

Units in python
GNU Lesser General Public License v3.0
24 stars 10 forks source link

Simpler unit conversions #3

Open mmarchetti opened 6 years ago

mmarchetti commented 6 years ago

Would you be willing to entertain a patch to make unit conversions easier?

I've experimented with two possibilities.

  1. Overriding __getitem__ to enable a bracket syntax for conversions:

    def __getitem__(self, index):
        if isinstance(index, Unum):
            return self.cast_unit(index)
        else:
            return Unum(self._value[index], self._unit)
  2. Overriding __or__ instead:

    def __or__(self, other):
        return self.cast_unit(other)

Examples:

>>> from unum.units.si import *
>>> from unum import Unum
>>> Unum.set_format(value_format='%.3f')
>>> arm_length = 320 * mm
>>> arm_mass = 65 * g
>>> gravity = 9.8 * m/s**2
>>> torque = 1/2 * arm_length * arm_mass * gravity
>>> torque
101920.000 [g·m·mm/s²]
# change to __getitem__ enables easy unit conversion,
# nicely matching the default output format:
>>> torque [N*m]
0.102 [N·m]
# Unfortunately expressions require parentheses, because [] binds more tightly.
>>> (torque / arm_length) [N]
0.319 [N]
# This example will fail because arm_length is not in Newtons:
# torque / arm_length [N]

# Alternately, overriding __or__ allows both of these to work:
>>> torque | N*m
0.102 [N·m]
>>> torque / arm_length | N
0.319 [N]
trzemecki commented 6 years ago

I think it would be better to use some external function, e.g. change as_unum to


def as_unum(value, unit=None):
    if unit is not None and not is_unit(unit):
        raise NonBasicUnitError(unit)

    if isinstance(value, Unum):
        if unit is not None:
            value = value.cast_unit(unit)

        return value

    return Unum(value) if unit is None else value * unit

>>> as_unum(torque, N*m)
0.102 [N·m]