In some cases you might want to use pint with a pre-existing web service or library which is not units aware. Or you might want to write a fast implementation of a numerical algorithm that requires the input values in some specific units.
For example, consider a function to return the period of the pendulum within a hypothetical physics library. The library does not use units, but instead requires you to provide numerical values in certain units:
>>> from simple_physics import pendulum_period
>>> help(pendulum_period)
Help on function pendulum_period in module simple_physics:
pendulum_period(length)
Return the pendulum period in seconds. The length of the pendulum
must be provided in meters.
>>> pendulum_period(1)
2.0064092925890407
This behaviour is very error prone, in particular when combining multiple libraries. You could wrap this function to use Quantities instead:
>>> from pint import UnitRegistry
>>> ureg = UnitRegistry()
>>> def mypp_caveman(length):
... return pendulum_period(length.to(ureg.meter).magnitude) * ureg.second
and:
>>> mypp_caveman(100 * ureg.centimeter)
<Quantity(2.0064092925890407, 'second')>
Pint provides a more convenient way to do this:
>>> mypp = ureg.wraps(ureg.second, ureg.meter)(pendulum_period)
To understand the syntax, consider the usage in the decorator format:
>>> @ureg.wraps(ureg.second, ureg.meter)
... def mypp(length):
... return pendulum_period(length)
wraps takes 3 input arguments:
- **ret**: the return units.
Use None to skip conversion.
- **args**: the inputs units for each argument, as an iterable.
Use None to skip conversion of any given element.
- **strict**: if `True` all convertible arguments must be a Quantity
and others will raise a ValueError (True by default)
>>> mypp(100 * ureg.centimeter)
<Quantity(2.0064092925890407, 'second')>
By default, the function is wrapped in strict mode. In this mode, the input arguments assigned to units must be a Quantities.
>>> mypp(1. * ureg.meter)
<Quantity(2.0064092925890407, 'second')>
>>> mypp(1.)
Traceback (most recent call last):
...
ValueError: A wrapped function using strict=True requires quantity for all arguments with not None units. (error found for meter, 1.0)
To enable using non-Quantity numerical values, set strict to False`.
>>> mypp_ns = ureg.wraps(ureg.second, ureg.meter, False)(pendulum_period)
>>> mypp_ns(1. * ureg.meter)
<Quantity(2.0064092925890407, 'second')>
>>> mypp_ns(1.)
<Quantity(2.0064092925890407, 'second')>
In this mode, the value is assumed to have the correct units.
For a function with more arguments, use a tuple:
>>> from simple_physics import pendulum_period2
>>> help(pendulum_period2)
Help on function pendulum_period2 in module simple_physics:
pendulum_period2(length, swing_amplitude)
Return the pendulum period in seconds. The length of the pendulum
must be provided in meters. The swing_amplitude must be in radians.
>>> mypp2 = ureg.wraps(ureg.second, (ureg.meter, ureg.radians))(pendulum_period2)
...
Or if the function has multiple outputs:
>>> mypp3 = ureg.wraps((ureg.second, ureg.meter / ureg.second),
... (ureg.meter, ureg.radians))(pendulum_period_maxspeed)
...
To avoid the conversion of an argument or return value, use None
>>> mypp3 = ureg.wraps((ureg.second, None), ureg.meter)(pendulum_period_error)