Skip to main content

Unit-safe computations with quantities

Project description

The package quantity provides classes for unit-safe computations with quantities.

Defining a quantity class

A basic type of quantity is declared just by sub-classing the class Quantity:

>>> class Length(Quantity):
...     pass
...

In addition to the new quantity class the meta-class of class Quantity creates a corresponding class for the units automatically. It can be referenced via the quantity class:

>>> Length.Unit
<class 'quantity.quantity.LengthUnit'>

If the quantity has a unit which is used as a reference for defining other units, the simplest way to define it is giving a name and a symbol for it as class variables. The meta-class of class Quantity will then create a unit automatically:

>>> class Length(Quantity):
...     refUnitName = 'Meter'
...     refUnitSymbol = 'm'
...
>>> Length.refUnit
Length.Unit('m')

Now, this unit can be given to create a quantity:

>>> METER = Length.refUnit
>>> print(Length(15, METER))
15 m

If no unit is given, the reference unit is used:

>>> print(Length(15))
15 m

Other units can be derived from the reference unit (or another unit), giving a definition by multiplying a scaling factor with that unit:

>>> MILLIMETER = Length.Unit('mm', 'Millimeter', Decimal('0.001') * METER)
>>> MILLIMETER
Length.Unit('mm')
>>> KILOMETER = Length.Unit('km', 'Kilometer', 1000 * METER)
>>> KILOMETER
Length.Unit('km')
>>> CENTIMETER = Length.Unit('cm', 'Centimeter', 10 * MILLIMETER)
>>> CENTIMETER
Length.Unit('cm')

Using one unit as a reference and defining all other units by giving a scaling factor is only possible if the units have the same scale. Otherwise, units have to be instantiated via the coresponding class Unit sub-class without giving a definition.

>>> class Temperature(Quantity):
...     pass
...
>>> CELSIUS = Temperature.Unit('°C', 'Degree Celsius')
>>> FAHRENHEIT = Temperature.Unit('°F', 'Degree Fahrenheit')

Derived types of quantities are declared by giving a definition based on more basic types of quantities:

>>> class Volume(Quantity):
...     defineAs = Length ** 3
...     refUnitName = 'Cubic Meter'
...
>>> class Duration(Quantity):
...     refUnitName = 'Second'
...     refUnitSymbol = 's'
...
>>> class Velocity(Quantity):
...     defineAs = Length / Duration
...     refUnitName = 'Meter per Second'
...

If no symbol for the reference unit is given with the class declaration, a symbol is generated from the definition, as long as all types of quantities in that definition have a reference unit.

>>> print(Volume.refUnit.symbol)
m³
>>> print(Velocity.refUnit.symbol)
m/s

Instantiating quantities

The simplest way to create an instance of a class Quantity subclass is to call the class giving an amount and a unit. If the unit is omitted, the quantity’s reference unit is used (if one is defined).

>>> Length(15, MILLIMETER)
Length(Decimal(15), Length.Unit(u'mm'))
>>> Length(15)
Length(Decimal(15))

Alternatively, the two-args infix operator ‘^’ can be used to combine an amount and a unit:

>>> 17.5 ^ KILOMETER
Length(Decimal('17.5'), Length.Unit(u'km'))

Also, it’s possible to create a Quantity sub-class instance from a string representation:

>>> Length('17.5 km')
Length(Decimal('17.5'), Length.Unit(u'km'))

Instead of calling a subclass, the class Quantity can be used as a factory function …

>>> Quantity(15, MILLIMETER)
Length(Decimal(15), Length.Unit(u'mm'))
>>> Quantity('17.5 km')
Length(Decimal('17.5'), Length.Unit(u'km'))

Unit-safe computations

A quantity can be converted to a quantity using a different unit by calling the method Quantity.convert:

>>> l5cm = Length(Decimal(5), CENTIMETER)
>>> l5cm.convert(MILLIMETER)
Length(Decimal('50'), Length.Unit('mm'))
>>> l5cm.convert(KILOMETER)
Length(Decimal('0.00005'), Length.Unit('km'))

Quantities can be compared to other quantities using all comparison operators defined for numbers. Different units are taken in to account automatically, as long as they are compatible, i. e. a conversion is available:

>>> Length(27) <= Length(91)
True
>>> Length(27, METER) <= Length(91, CENTIMETER)
False

Quantities can be added to or subtracted from other quantities …

>>> Length(27) + Length(9)
Length(Decimal(36))
>>> Length(27) - Length(91)
Length(Decimal(-64))
>>> Length(27) + Length(12, CENTIMETER)
Length(Decimal('27.12'))
>>> Length(12, CENTIMETER) + Length(17, METER)
Length(Decimal('1712'), Length.Unit('cm'))

… as long as they are instances of the same quantity type:

>>> Length(27) + Duration(9)
quantity.quantity.IncompatibleUnitsError: Can't add a 'Length' and a
    'Duration'

Quantities can be multiplied or divided by scalars, preserving the unit:

>>> 7.5 * Length(3, CENTIMETER)
Length(Decimal('22.5'), Length.Unit(u'cm'))
>>> Duration(66, MINUTE) / 11
Duration(Decimal(6), Duration.Unit(u'min'))

Quantities can be multiplied or divided by other quantities …:

>>> Length(15, METER) / Duration(3, SECOND)
Velocity(Decimal(5))

… as long as the resulting type of quantity is defined …:

>>> Duration(4, SECOND) * Length(7)
UndefinedResultError: Undefined result: Duration * Length

… or the result is a scalar:

>>> Duration(2, MINUTE) / Duration(50, SECOND)
Decimal('2.4')

Quantities can be raised by an exponent, as long as the exponent is an Integral number and the resulting quantity is defined:

>>> (5 ^ METER) ** 2
Area(Decimal(25))
>>> (5 ^ METER) ** 2.5
TypeError: unsupported operand type(s) for ** or pow(): 'Length' and
    'float'
>>> (5 ^ METER) ** -2
UndefinedResultError: Undefined result: Length ** -2

For more details see the documentation provided with the source distribution or here.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

quantity-0.7.0.tar.gz (324.0 kB view details)

Uploaded Source

File details

Details for the file quantity-0.7.0.tar.gz.

File metadata

  • Download URL: quantity-0.7.0.tar.gz
  • Upload date:
  • Size: 324.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No

File hashes

Hashes for quantity-0.7.0.tar.gz
Algorithm Hash digest
SHA256 5e5d82178405d54cae619d96ac9d60b2ac7ac823cb80dfaf00645ededd5436fe
MD5 146b8c39d097a9c8ef2c1cb8a361fbda
BLAKE2b-256 e9b6390e3d99b9feb86cbafe54721ff4c0ccc6860f23941093cf4e44d62f930a

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page