If you want to try the same example I used to described the desired behavior for a language incorporated unit of measure, you can enter the following line and Pint will also raise an exception because it cannot convert volts to ohms. In this case, the code mixes three incompatible units: volts, ohms, and inches.

You can also perform operations in compatible complex units. For example, the following code assigns 2 miles per minute to speed1 and 100 kilometers per hour to speed2. Then, the total_speed variable holds a Quantity instance with the result of adding the two speed values.

In this case, the unit of measure associated with total_speed is miles per minute (mile / minute for Pint) because Pint converts the other value to the unit associated with the first variable (speed1). You have to be careful with this precedence of the operators because if you change the last line with the following line, the unit of measure associated with total_speed is going to be kilometers per hour (kilometer / hour for Pint) because the first variable is speed2:

total_speed = speed2 + speed1

Thus, if you want to be sure of the unit of measure that the resulting Quantity object will use, it is convenient to specify it, as in the next line:

total_speed = (speed2 + speed1).to(ur.miles / ur.minute)

There are many other ways to create a Quantity instance with a value and an associated unit of measure. The following lines are equivalent and use the Quantity constructor instead of multiplication. The Quantity constructor can parse both units and values.

Each time you are defining a new value with an associated unit of measure, you are creating a new instance of Quantity; therefore, Pint introduces a performance overhead compared with working with just numeric values. However, Pint provides the necessary features to avoid the most common mistakes related to working with values expressed in different units of measure and extremely powerful customization options. In addition, the unit conversion features allow you to simplify your code and focus on your problem domain because the most common units are already defined with good accuracy.

Units: A Different Approach

Units is another Python package that allows you to work with numerical values associated to units of measure. Unit provides unit objects that you use to create Quantity instances that save the magnitude and the associated units for any numerical type. You can perform arithmetic operations between compatible units. When you try to perform arithmetic operations on magnitudes that have incompatible units of measure, Unit raises a units.exception.IncompatibleUnitsError exception indicating that it cannot perform the operation when the units are different. However, Units doesn't allow you to work with prefixes, so it doesn't provide a complete set of unit conversion capabilities.

Units is easy to use and includes many common units already defined without the possibility of adding prefixes. You just need to add the following lines to import unit and predefined from units and call the define_units method that initializes the most common units included in the package. You can check the predefined units by checking the source code of predefined.py.

from units import unit, predefined
units.predefined.define_units()

Then, to assign a unit of measure to a value, use the unit object with the desired units of measure and pass the desired value as a parameter. Units will create an instance of the Quantity class. The num property will hold the specified value and the unit property will include the units of measure.

You can read the following line of code as "assign 500 ohms to r1."

r1 = unit('Ohm')(500)

If you call print(r1) the result will be 500.00 Ohm. If you enter r1 in the Python Console, the result will be:

As you can see, the way in which Units stores the composed unit is a bit complex, but you can easily check the unit with the help of the unit object. For example, the following expression will be True:

r1.unit == unit('Ohm')

Because Units doesn't define a kilo-Ohm unit, if you want to be able to convert from Ohms to kilo-ohms, you need to create the kilo-Ohm unit as a scalar multiple of the existing Ohm unit. The following code creates the new unit and displays the value of r1 in kilo-Ohm:

The following line displays the value of r1 expressed in ohms, no matter the unit in which r1 has the value saved.

print(unit('Ohm')(r1))

The following code uses Units to sum the values of r1 and r2. The r1_plus_r2 variable holds the result of the sum operation expressed in ohms and r1_plus_r2_kiloOhm holds the result converted to the new unit defined in the previous code, kilo-Ohm. I don't use kilo-ohms just to follow the way Units works with the predefined units, without plurals. Units performs the necessary conversion to allow you to sum the values of r1 and r2.

However, if you try to sum the four distances with the following line, Units will raise a units.exception.IncompatibleUnitsError because the four units are different.

total_distance = distance1 + distance2 + distance3 + distance4

Conclusion

Of the packages discussed in this article, Numericalunits is very simple, but it doesn't avoid the most common problems. Pint is definitely the most complete package when you just want to focus on the problem domain and take advantage of the prefixes, plurals, alias names, and the simple customization of the units definition file. Units provides basic features that you can improve by defining your own units. If you have to write an algorithm that involves complex formulas with different units of measure in Python, you will definitely want to consider one of these packages before reinventing the wheel.

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task.
However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

Video

This month's Dr. Dobb's Journal

This month,
Dr. Dobb's Journal is devoted to mobile programming. We introduce you to Apple's new Swift programming language, discuss the perils of being the third-most-popular mobile platform, revisit SQLite on Android
, and much more!