Unitted Functions

A function which handles UnitArrays and UnitScalars is a unitted function. Unitted functions are created with the has_units() decorator. The units can be specified by passing arguments to the decorator or by constructing a special docstring.

Decorator arguments

from numpy import array
from scimath.units.api import has_units
from scimath.units.length import feet, meter
@has_units(inputs="a:an array:units=ft;b:array:units=ft",
           outputs="result:an array:units=m")
def add(a,b):
    """ Add two arrays in ft and convert them to m.

    """
    return (a + b) * feet / meter

To use has_units with decorator arguments, pass string arguments “inputs” and (optionally) “outputs”. See the has_units() docstring or visit the User Reference page for details on the syntax.

Formatted docstring

from scimath.units.api import has_units, UnitArray
@has_units
def add(a,b):
    """ Add two arrays in ft and convert them to m.

        Parameters
        ----------
        a : array : units=ft
            An array
        b : array : units=ft
            Another array

        Returns
        -------
        c : array : units=m
            c = a + b
    """
    return (a + b) * feet / meter

Using the has_units decorator with a docstring has the benefit of using a ReST-compatible format, so the unitting specification doubles as a documentation entry. See the has_units() docstring or visit the User Reference page for details on the syntax. The example above produces the following documentation entry when built with Sphinx:

Unitted function output

In the examples above, we told add() to expect two values, a and b and convert them to feet for use in the function. Then we specified that the output would be in meters. Inside the function, a and b are not unitted, and the function is responsible for the conversion. (Remember our caveat regarding conversion factors.)

Unitted functions can accept either regular Python objects (of the appropriate type) or the equivalent unitted objects. The return type depends on what it was passed.

>>> add(1,2)
0.9144000000000001

In this case, add() accepted two integer arguments in feet, added them and returned an integer value in meters.

>>> add(UnitScalar(1, units="foot"), UnitScalar(2, units="foot"))
UnitScalar(0.9144000000000001, units='1.0*m')

In this case, add() accepted two UnitScalar arguments in feet and returned a UnitScalar in pure meters.

>>> add(UnitScalar(0.5, units="meter"), UnitScalar(50, units="cm"))
UnitScalar(1.0, units='1.0*m')

Finally, in this case, a conversion to feet was made for the calculation inside the function, and the value was converted back to meters when returned.

If no units are specified in the outputs or if no output string is given, then a regular scalar data type will be returned.

It may be useful to define new units for use in a project and have them available throughout an application. This is done by extending the unit parser to handle user-defined units, described in the next section.