numbers —数値の抽象基本クラス
ソースコード: :source: `Lib / numbers.py`
numbers モジュール( PEP 3141 )は、より多くの操作を段階的に定義する数値抽象基本クラスの階層を定義します。 このモジュールで定義されているタイプはいずれも、インスタンス化することを目的としていません。
- class numbers.Number
- 数値階層のルート。 引数 x が数値かどうかを確認したいだけで、種類を気にしない場合は、
isinstance(x, Number)
を使用します。
数値タワー
- class numbers.Complex
このタイプのサブクラスは、複素数を記述し、組み込みの complex タイプで機能する操作を含みます。 これらは、 complex および bool 、 real 、 imag 、
+
、-
への変換です。 、*
、/
、**
、 abs()、conjugate()
、==
、および!=
。-
と!=
を除くすべてが抽象的です。- real
概要。 この数値の実数成分を取得します。
- imag
概要。 この数値の虚数成分を取得します。
- class numbers.Real
Complex に、 Real は実数で機能する演算を追加します。
つまり、 float 、 math.trunc()、 round()、 math.floor()への変換です。 、 math.ceil()、 divmod()、
//
、%
、<
、<=
、>
、および>=
。
- class numbers.Rational
Real をサブタイプ化し、分子および分母プロパティを追加します。 これらを使用すると、 float()のデフォルトが提供されます。
- numerator
概要。
- denominator
概要。
- class numbers.Integral
- Rational をサブタイプ化し、 int への変換を追加します。 float()、分子、および分母のデフォルトを提供します。 モジュラスおよびビット文字列演算を使用した pow()の抽象メソッドを追加します:
<<
、>>
、&
、^
、[ X125X] 、~
。
タイプ実装者向けの注意事項
実装者は、等しい数を等しくし、それらを同じ値にハッシュするように注意する必要があります。 実数の2つの異なる拡張子がある場合、これは微妙な場合があります。 たとえば、 fractions.Fraction は、 hash()を次のように実装します。
def __hash__(self):
if self.denominator == 1:
# Get integers right.
return hash(self.numerator)
# Expensive check, but definitely correct.
if self == float(self):
return hash(float(self))
else:
# Use tuple's hash to avoid a high collision rate on
# simple fractions.
return hash((self.numerator, self.denominator))
数値ABCの追加
もちろん、数字に対してより多くの可能性のあるABCがあり、それらを追加する可能性を排除した場合、これは貧弱な階層になります。 Complex と Real の間にMyFoo
を追加するには、次のようにします。
class MyFoo(Complex): ...
MyFoo.register(Real)
算術演算の実装
算術演算を実装して、混合モード演算が、作成者が両方の引数の型について知っている実装を呼び出すか、両方を最も近い組み込み型に変換してそこで演算を実行するようにします。 Integral のサブタイプの場合、これは__add__()
および__radd__()
を次のように定義する必要があることを意味します。
class MyIntegral(Integral):
def __add__(self, other):
if isinstance(other, MyIntegral):
return do_my_adding_stuff(self, other)
elif isinstance(other, OtherTypeIKnowAbout):
return do_my_other_adding_stuff(self, other)
else:
return NotImplemented
def __radd__(self, other):
if isinstance(other, MyIntegral):
return do_my_adding_stuff(other, self)
elif isinstance(other, OtherTypeIKnowAbout):
return do_my_other_adding_stuff(other, self)
elif isinstance(other, Integral):
return int(other) + int(self)
elif isinstance(other, Real):
return float(other) + float(self)
elif isinstance(other, Complex):
return complex(other) + complex(self)
else:
return NotImplemented
Complex のサブクラスでの混合型操作には5つの異なるケースがあります。 MyIntegral
およびOtherTypeIKnowAbout
を参照しない上記のすべてのコードを「ボイラープレート」と呼びます。 a
は、 Complex (a : A <: Complex
)およびb : B <: Complex
のサブタイプであるA
のインスタンスになります。 a + b
を検討します:
A
がb
を受け入れる__add__()
を定義している場合、すべてが順調です。A
がボイラープレートコードにフォールバックし、__add__()
から値を返す場合、B
がよりインテリジェントな [を定義する可能性を見逃します。 X167X]なので、ボイラープレートは__add__()
から NotImplemented を返す必要があります。 (または、A
は__add__()
をまったく実装しない場合があります。)- 次に、
B
の__radd__()
がチャンスを獲得します。a
を受け入れる場合は、すべて問題ありません。- ボイラープレートにフォールバックした場合、試すことができる方法はこれ以上ないため、これがデフォルトの実装が存在する場所です。
B <: A
の場合、PythonはA.__add__
の前にB.__radd__
を試行します。A
の知識で実装されているため、これは問題ありません。 Complex に委任する前にこれらのインスタンスを処理できます。
他の知識を共有せずにA <: Complex
とB <: Real
の場合、適切な共有操作は、組み込みの複合体と、両方の__radd__()
の土地を含む操作です。そこで、a+b == b+a
。
特定のタイプに対する操作のほとんどは非常に類似しているため、特定の演算子の順方向インスタンスと逆方向インスタンスを生成するヘルパー関数を定義すると便利です。 たとえば、 fractions.Fraction は次を使用します。
def _operator_fallbacks(monomorphic_operator, fallback_operator):
def forward(a, b):
if isinstance(b, (int, Fraction)):
return monomorphic_operator(a, b)
elif isinstance(b, float):
return fallback_operator(float(a), b)
elif isinstance(b, complex):
return fallback_operator(complex(a), b)
else:
return NotImplemented
forward.__name__ = '__' + fallback_operator.__name__ + '__'
forward.__doc__ = monomorphic_operator.__doc__
def reverse(b, a):
if isinstance(a, Rational):
# Includes ints.
return monomorphic_operator(a, b)
elif isinstance(a, numbers.Real):
return fallback_operator(float(a), float(b))
elif isinstance(a, numbers.Complex):
return fallback_operator(complex(a), complex(b))
else:
return NotImplemented
reverse.__name__ = '__r' + fallback_operator.__name__ + '__'
reverse.__doc__ = monomorphic_operator.__doc__
return forward, reverse
def _add(a, b):
"""a + b"""
return Fraction(a.numerator * b.denominator +
b.numerator * a.denominator,
a.denominator * b.denominator)
__add__, __radd__ = _operator_fallbacks(_add, operator.add)
# ...