From 3a1d475c5141e2e0fc3049a72e616da534824054 Mon Sep 17 00:00:00 2001 From: Clark Willison Date: Mon, 13 Jul 2020 23:34:06 -0700 Subject: move some content from tutorial to new page this commit adds a new page to the docs about the various ways of defining quantity objects in Pint, and moves some of the content from the tutorial in there not certain if it's a better arrangement, the theory is that a more concise tutorial with links to more detailed pages might get users up and running faster very open to suggestions though --- docs/contexts.rst | 1 - docs/defining-quantities.rst | 142 ++++++++++++++++++++++++++++++++++++++++ docs/index.rst | 1 + docs/tutorial.rst | 152 +++++++++++++++---------------------------- 4 files changed, 194 insertions(+), 102 deletions(-) create mode 100644 docs/defining-quantities.rst (limited to 'docs') diff --git a/docs/contexts.rst b/docs/contexts.rst index 9f75c9f..4077503 100644 --- a/docs/contexts.rst +++ b/docs/contexts.rst @@ -1,4 +1,3 @@ -.. _contexts: Contexts ======== diff --git a/docs/defining-quantities.rst b/docs/defining-quantities.rst new file mode 100644 index 0000000..b0126f3 --- /dev/null +++ b/docs/defining-quantities.rst @@ -0,0 +1,142 @@ +Defining Quantities +=================== + +A quantity in Pint is the product of a unit and a magnitude. + +Pint supports several different ways of defining physical quantities, including +a powerful string parsing system. These methods are largely interchangeable, +though you may **need** to use the constructor form under certain circumstances +(see :doc:`nonmult` for an example of where the constructor form is required). + +By multiplication +----------------- + +If you've read the :ref:`Tutorial`, you're already familiar with defining a +quantity by multiplying a ``Unit()`` and a scalar: + +.. doctest:: + + >>> from pint import UnitRegistry + >>> ureg = UnitRegistry() + >>> ureg.meter + + >>> 30.0 * ureg.meter + + +This works to build up complex units as well: + +.. doctest:: + + >>> 9.8 * ureg.meter / ureg.second**2 + + + +Using the constructor +--------------------- + +In some cases it is useful to define :class:`Quantity() ` +objects using it's class constructor. Using the constructor allows you to +specify the units and magnitude separately. + +We typically abbreviate that constructor as `Q_` to make it's usage less verbose: + +.. doctest:: + + >>> Q_ = ureg.Quantity + >>> Q_(1.78, ureg.meter) + + +As you can see below, the multiplication and constructor methods should produce +the same results: + +.. doctest:: + + >>> Q_(30.0, ureg.meter) == 30.0 * ureg.meter + True + >>> Q_(9.8, ureg.meter / ureg.second**2) + + + +Using string parsing +-------------------- + +Pint includes a powerful parser for detecting magnitudes and units (with or +without prefixes) in strings. Calling the ``UnitRegistry()`` directly +invokes the parsing function: + +.. doctest:: + + >>> 30.0 * ureg('meter') + + >>> ureg('30.0 meters') + + >>> ureg('3000cm').to('meters') + + +The parsing function is also available to the ``Quantity()`` constructor and +the various ``.to()`` methods: + +.. doctest:: + + >>> Q_('30.0 meters') + + >>> Q_(30.0, 'meter') + + >>> Q_('3000.0cm').to('meter') + + +Or as a standalone method on the ``UnitRegistry``: + +.. doctest:: + + >>> 2.54 * ureg.parse_expression('centimeter') + + +It is fairly good at detecting compound units: + +.. doctest:: + + >>> g = ureg('9.8 meters/second**2') + >>> g + + >>> g.to('furlongs/fortnight**2') + + +And behaves well when given dimensionless quantities, which are parsed into +their appropriate objects: + +.. doctest:: + + >>> ureg('2.54') + 2.54 + >>> type(ureg('2.54')) + + >>> Q_('2.54') + + >>> type(Q_('2.54')) + .Quantity'> + +.. note:: Pint's rule for parsing strings with a mixture of numbers and + units is that **units are treated with the same precedence as numbers**. + +For example, the units of + +.. doctest:: + + >>> Q_('3 l / 100 km') + + +may be unexpected at first but, are a consequence of applying this rule. Use +brackets to get the expected result: + +.. doctest:: + + >>> Q_('3 l / (100 km)') + + +.. note:: Since version 0.7, Pint **does not** use eval_ under the hood. + This change removes the `serious security problems`_ that the system is + exposed to when parsing information from untrusted sources. + +.. _eval: http://docs.python.org/3/library/functions.html#eval +.. _`serious security problems`: http://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html diff --git a/docs/index.rst b/docs/index.rst index 4d045e3..5bbbd51 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -119,6 +119,7 @@ User Guide getting tutorial + defining-quantities numpy nonmult wrapping diff --git a/docs/tutorial.rst b/docs/tutorial.rst index a174a12..e473ac4 100644 --- a/docs/tutorial.rst +++ b/docs/tutorial.rst @@ -2,10 +2,11 @@ Tutorial ======== -Follow the steps below to get up and running quickly with Pint. +Follow the steps below and learn how to use Pint to track physical quantities +and perform unit conversions in Python. -Initialize a Registry ---------------------- +Initializing a Registry +----------------------- Before using Pint, initialize a :class:`UnitRegistry() ` object. The ``UnitRegistry`` stores the unit definitions, their relationships, @@ -19,10 +20,10 @@ and handles conversions between units. If no parameters are given to the constructor, the ``UnitRegistry`` is populated with the `default list of units`_ and prefixes. -Define a Quantity ------------------ +Defining a Quantity +------------------- -Once you've initialized your registry, you can define quantities easily: +Once you've initialized your ``UnitRegistry``, you can define quantities easily: .. doctest:: @@ -45,7 +46,7 @@ magnitude, units, and dimensionality: >>> print(distance.dimensionality) [length] -and can handle many mathematical operations, including with other +and can correctly handle many mathematical operations, including with other :class:`Quantity() ` objects: .. doctest:: @@ -61,13 +62,40 @@ and can handle many mathematical operations, including with other >>> print(speed.dimensionality) [length] / [time] -See `String parsing`_ for more ways of defining a ``Quantity()`` object. +Notice the built-in parser recognizes prefixed and pluralized units even though +they are not in the definition list: + +.. doctest:: + + >>> distance = 42 * ureg.kilometers + >>> print(distance) + 42 kilometer + >>> print(distance.to(ureg.meter)) + 42000.0 meter + +Pint will complain if you try to use a unit which is not in the registry: + +.. doctest:: + + >>> speed = 23 * ureg.snail_speed + Traceback (most recent call last): + ... + UndefinedUnitError: 'snail_speed' is not defined in the unit registry + +You can add your own units to the existing registry, or build your own list. +See the page on :ref:`defining` for more information on that. + +See `String parsing`_ and :doc:`defining-quantities` for more ways of defining +a ``Quantity()`` object. + +``Quantity()`` objects also work well with NumPy arrays, which you can +read about in the section on :doc:`NumPy support `. Converting to Different Units ----------------------------- -As the underlying ``UnitRegistry`` knows about the relationship between -different units, you can convert quantities to the units of your choice using +As the underlying ``UnitRegistry`` knows the relationships between +different units, you can convert a ``Quantity`` to the units of your choice using the ``to()`` method, which accepts a string or a :class:`Unit() ` object: .. doctest:: @@ -97,7 +125,8 @@ use the ``ito()`` method: >>> print(speed) 7086.6141... inch / minute -If you ask Pint to perform an invalid conversion: +Pint will complain if you ask it to perform a conversion it doesn't know +how to do: .. doctest:: @@ -106,6 +135,12 @@ If you ask Pint to perform an invalid conversion: ... DimensionalityError: Cannot convert from 'inch / minute' ([length] / [time]) to 'joule' ([length] ** 2 * [mass] / [time] ** 2) +See the section on :doc:`contexts` for information about expanding Pint's +automatic conversion capabilities for your application. + +Simplifying units +----------------- + Sometimes, the magnitude of the quantity will be very large or very small. The method ``to_compact()`` can adjust the units to make a quantity more human-readable: @@ -158,50 +193,11 @@ If you want pint to automatically perform dimensional reduction when producing new quantities, the ``UnitRegistry`` class accepts a parameter ``auto_reduce_dimensions``. Dimensional reduction can be slow, so auto-reducing is disabled by default. -In some cases it is useful to define physical quantities objects using the -class constructor: - -.. doctest:: - - >>> Q_ = ureg.Quantity - >>> Q_(1.78, ureg.meter) == 1.78 * ureg.meter - True - -(I tend to abbreviate Quantity as ``Q_``) The built-in parser recognizes prefixed -and pluralized units even though they are not in the definition list: - -.. doctest:: - - >>> distance = 42 * ureg.kilometers - >>> print(distance) - 42 kilometer - >>> print(distance.to(ureg.meter)) - 42000.0 meter - -Pint will complain if you try to use a unit which is not in the registry: - -.. doctest:: - - >>> speed = 23 * ureg.snail_speed - Traceback (most recent call last): - ... - UndefinedUnitError: 'snail_speed' is not defined in the unit registry - -You can add your own units to the existing registry, or build your own list. -See the page on :ref:`defining` units for more information on that. - - String parsing -------------- -Pint can also handle units provided as strings: - -.. doctest:: - - >>> 2.54 * ureg.parse_expression('centimeter') - - -or using the registry as a callable for a short form for ``parse_expression()``: +Pint includes powerful string parsing for identifying magnitudes and units. In +many cases, units can be defined as strings: .. doctest:: @@ -212,6 +208,7 @@ or using the ``Quantity`` constructor: .. doctest:: + >>> Q_ = ureg.Quantity >>> Q_(2.54, 'centimeter') @@ -221,11 +218,6 @@ Numbers are also parsed, so you can use an expression: >>> ureg('2.54 * centimeter') - -or: - -.. doctest:: - >>> Q_('2.54 * centimeter') @@ -245,47 +237,6 @@ This enables you to build a simple unit converter in 3 lines: >>> Q_(src).to(dst) -Dimensionless quantities can also be parsed into an appropriate object: - -.. doctest:: - - >>> ureg('2.54') - 2.54 - >>> type(ureg('2.54')) - - -or - -.. doctest:: - - >>> Q_('2.54') - - >>> type(Q_('2.54')) - .Quantity'> - -.. note:: Pint´s rule for parsing strings with a mixture of numbers and - units is that **units are treated with the same precedence as numbers**. - -For example, the units of - -.. doctest:: - - >>> Q_('3 l / 100 km') - - -may be unexpected at first but, are a consequence of applying this rule. Use -brackets to get the expected result: - -.. doctest:: - - >>> Q_('3 l / (100 km)') - - -.. note:: Since version 0.7, Pint **does not** use eval_ under the hood. - This change removes the `serious security problems`_ that the system is - exposed to when parsing information from untrusted sources. - - Strings containing values can be parsed using the ``ureg.parse_pattern()`` function. A ``format``-like string with the units defined in it is used as the pattern: @@ -317,7 +268,8 @@ The full power of regex can also be employed when writing patterns: *Note that the curly brackets (``{}``) are converted to a float-matching pattern by the parser.* -This function is useful for tasks such as bulk extraction of units from thousands of uniform strings or even very large texts with units dotted around in no particular pattern. +This function is useful for tasks such as bulk extraction of units from thousands +of uniform strings or even very large texts with units dotted around in no particular pattern. .. _sec-string-formatting: @@ -523,8 +475,6 @@ also define the registry as the application registry .. _`default list of units`: https://github.com/hgrecco/pint/blob/master/pint/default_en.txt -.. _eval: http://docs.python.org/3/library/functions.html#eval -.. _`serious security problems`: http://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html .. _`Babel`: http://babel.pocoo.org/ .. _`formatting syntax`: https://docs.python.org/3/library/string.html#format-specification-mini-language .. _`f-strings`: https://www.python.org/dev/peps/pep-0498/ -- cgit v1.2.1