/var/log/messages

Jan 26, 2018 - 6 minute read - Comments - python

Pint Tutorial

Pint Tutorialをぐーぐる翻訳にかけつつ試してみたので以下に控えておきます。無許可です。すみません。

Converting Quantities

Pint には ユニットが定義されて処理されるオブジェクトとしての Unit Registry という概念があります。まず、レジストリを作成します:

>>> from pint import UnitRegistry
>>> ureg = UnitRegistry()

コンストラクタにパラメータが与えられていない場合、Unit Registry にはユニットとプレフィックスのデフォルトリストが設定されます。これでレジストリを以下のように簡単に使用できるようになります:

>>> distance = 24.0 * ureg.meter
>>> print(distance)
24.0 meter
>>> time = 8.0 * ureg.second
>>> print(time)
8.0 second
>>> print(repr(time))
<Quantity(8.0, 'second')>

このコードでは、距離と時間は物理量オブジェクト (Quantify) です。物理量はその大きさ、単位、および次元について問い合わせることができます:

>>> print(distance.magnitude)
24.0
>>> print(distance.units)
meter
>>> print(distance.dimensionality)
[length]

そして、以下のような数値演算の処理が可能です:

>>> speed = distance / time
>>> print(speed)
3.0 meter / second

Unit Registry が異なるユニット間の関係を知っているので、数量を選択ユニットに変換することが可能です:

>>> speed.to(ureg.inch / ureg.minute )
<Quantity(7086.614173228345, 'inch / minute')>

このメソッドは、元のオブジェクトへの副作用はありません(値は元のままです)。

>>> print(speed)
3.0 meter / second

インプレース(別のオブジェクトを作成せずに)に変換する場合は、ito メソッドを使用することが可能です:

>>> speed.ito(ureg.inch / ureg.minute )
>>> speed
<Quantity(7086.614173228345, 'inch / minute')>
>>> print(speed)
7086.614173228345 inch / minute

Pint に無効な変換を依頼する場合:

>>> speed.to(ureg.joule)
Traceback (most recent call last):
...
pint.errors.DimensionalityError: Cannot convert from 'inch / minute' ([length] / [time]) to 'joule' ([length] ** 2 * [mass] / [time] ** 2)

正しい次元を持つ参照単位に自動的に変換するメソッド ‘to_base_units’ と ‘ito_base_units’ もあります:

>>> height = 5.0 * ureg.foot + 9.0 * ureg.inch
>>> print(height)
5.75 foot
>>> print(height.to_base_units())
1.7526 meter
>>> print(height)
5.75 foot
>>> height.ito_base_units()
>>> print(height)
1.7526 meter

単純な次元削減を実行する、同じ次元を持つユニットを結合するが、それ以外の場合はユニット定義をそのまま維持するメソッド ‘to_reduced_units'と ‘ito_reduced_units'もあります。

>>> density = 1.4 * ureg.gram / ureg.cm**3
>>> volume = 10*ureg.cc
>>> mass = density*volume
>>> print(mass)
14.0 cc * gram / centimeter ** 3
>>> print(mass.to_reduced_units())
14.0 gram
>>> print(mass)
14.0 cc * gram / centimeter ** 3
>>> mass.ito_reduced_units()
>>> print(mass)
14.0 gram

新しい数量を生成するときに Pint が次元削減を自動的に実行するようにするには、Unit Registry は auto_reduce_dimensions パラメータを受け取ります。 次元削減は遅くなる可能性があるため、デフォルトでは自動削減は無効になっています。

場合によっては、クラスコンストラクタを使用して物理量オブジェクトを定義すると便利です:

>>> Q_ = ureg.Quantity
>>> Q_(1.78, ureg.meter) == 1.78 * ureg.meter
True

(私はQuantityをQ_と略記する傾向があります)組み込みパーサーは、定義リストにないにもかかわらず、プレフィックス付きの複数の単位を認識します:

>>> distance = 42 * ureg.kilometers
>>> print(distance)
42 kilometer
>>> print(distance.to(ureg.meter))
42000.0 meter

レジストリにないユニットを使用しようとすると:

>>> speed = 23 * ureg.snail_speed
Traceback (most recent call last):
...
pint.errors.UndefinedUnitError: 'snail_speed' is not defined in the unit registry]

独自のユニットをレジストリに追加したり、独自のリストを作成することができます。Defining units の詳細

String parsing

Pintは、文字列として提供されるユニットを扱うこともできます:

>>> 2.54 * ureg.parse_expression('centimeter')
<Quantity(2.54, 'centimeter')>

または parse_expression の短縮形のために呼び出し可能なものとしてレジストリを使用します:

>>> 2.54 * ureg('centimeter')
<Quantity(2.54, 'centimeter')>

またはQuantityコンストラクタを使用します:

>>> Q_(2.54, 'centimeter')
<Quantity(2.54, 'centimeter')>

数値もパースされるので、式を使うことができます:

>>> ureg('2.54 * centimeter')
<Quantity(2.54, 'centimeter')>

または:

>>> Q_('2.54 * centimeter')
<Quantity(2.54, 'centimeter')>

または * 全体を省略:

>>> Q_('2.54cm')
<Quantity(2.54, 'centimeter')>

これにより、簡単な単位コンバータを3行で構築することができます:

>>> user_input = '2.54 * centimeter to inch'
>>> src, dst = user_input.split(' to ')
>>> Q_(src).to(dst)
<Quantity(1.0, 'inch')>

次元のない量は、適切なオブジェクトに解析することもできます。:

>>> ureg('2.54')
2.54
>>> type(ureg('2.54'))
<class 'float'>

または

>>> Q_('2.54')
<Quantity(2.54, 'dimensionless')>
>>> type(Q_('2.54'))
<class 'pint.quantity.build_quantity_class.<locals>.Quantity'>

注:数字と単位が混在した文字列を解析するための Pint の規則は、単位が数字と同じ優先順位で扱われることです。

例えば、

>>> Q_('3 l / 100 km')
<Quantity(0.03, 'kilometer * liter')>

予期しないものである可能性がありますが、このルールを適用した結果です。 期待される結果を得るには括弧を使います:

>>> Q_('3 l / (100 km)')
<Quantity(0.03, 'liter / kilometer')>

注:バージョン0.7以来、Pint はフードの下で評価を使用しません。 この変更により、信頼されていない情報源からの情報を解析する際にシステムがさらされる重大なセキュリティ上の問題が取り除かれます。

String formatting

Pint の物理量は簡単に印字できます:

>>> accel = 1.3 * ureg['meter/second**2']
>>> # The standard string formatting code
>>> print('The str is {!s}'.format(accel))
The str is 1.3 meter / second ** 2
>>> # The standard representation formatting code
>>> print('The repr is {!r}'.format(accel))
The repr is <Quantity(1.3, 'meter / second ** 2')>
>>> # Accessing useful attributes
>>> print('The magnitude is {0.magnitude} with units {0.units}'.format(accel))
The magnitude is 1.3 with units meter / second ** 2

しかし Pint は、Unicode と LaTeX 表現のための標準フォーマット機能も拡張しています。

>>> accel = 1.3 * ureg['meter/second**2']
>>> # Pretty print
>>> 'The pretty representation is {:P}'.format(accel)
'The pretty representation is 1.3 meter/second²'
>>> # Latex print
>>> 'The latex representation is {:L}'.format(accel)
'The latex representation is 1.3\\ \\frac{\\mathrm{meter}}{\\mathrm{second}^{2}}'
>>> # HTML print
>>> 'The HTML representation is {:H}'.format(accel)
'The HTML representation is 1.3 meter/second<sup>2</sup>'

注:Python 2 では、UnicodeEncodeError を防ぐために、future import unicode_literals から、またはかなりフォーマットされた文字列の前に u を付けて実行してください。

省略されたユニット名を使用する場合は、指定に〜の前に接頭辞を付けます。

>>> 'The str is {:~}'.format(accel)
'The str is 1.3 m / s ** 2'
>>> 'The pretty representation is {:~P}'.format(accel)
'The pretty representation is 1.3 m/s²'

Latex (L) と HTML (H) の仕様についても同じことが言えます。

Pint は LaTeX の siunitx パッケージもサポートしています:

>>> accel = 1.3 * ureg['meter/second**2']
>>> # siunitx Latex print
>>> print('The siunitx representation is {:Lx}'.format(accel))
The siunitx representation is \SI[]{1.3}{\meter\per\second\squared}

さらに、デフォルトの書式指定を指定することもできます:

>>> 'The acceleration is {}'.format(accel)
'The acceleration is 1.3 meter / second ** 2'
>>> ureg.default_format = 'P'
>>> 'The acceleration is {}'.format(accel)
'The acceleration is 1.3 meter/second²'

最後に、Babel がインストールされている場合は、ユニット名を任意の言語に翻訳できます

>>> accel.format_babel(locale='fr_FR')
'1.3 mètre par seconde²'

Using Pint in your projects

Pythonパッケージ内の複数のモジュールで Pint を使用する場合、Unit Registry のインスタンスを複数作成しないでください。 これを行う最善の方法は、レジストリを単一の場所でインスタンス化することです。 たとえば、次のコードをパッケージ__init__.pyに追加することができます:

from pint import UnitRegistry
ureg = UnitRegistry()
Q_ = ureg.Quantity

次に、yourmodule.py のコードは次のようになります:

from . import ureg, Q_

length = 10 * ureg.meter
my_speed = Q_(20, 'm/s')

プロジェクト内の数量を pickling および unplicking する場合は、レジストリをアプリケーションレジストリとして定義する必要があります:

from pint import UnitRegistry, set_application_registry
ureg = UnitRegistry()
set_application_registry(ureg)

警告:Pint にはグローバルユニットはありません。 すべてのユニットはレジストリに属し、複数のレジストリを同時にインスタンス化することができます。 ただし、異なるレジストリに属する数量の間で操作することはできません。 このようなことは絶対にしないでください:

>>> q1 = 10 * UnitRegistry().meter
>>> q2 = 10 * UnitRegistry().meter
>>> q1 + q2
Traceback (most recent call last):
...
ValueError: Cannot operate with Quantity and Quantity of different registries.
>>> id(q1._REGISTRY) == id(q2._REGISTRY)
False

メモ python-OBD について

comments powered by Disqus