数値—数値抽象基本クラス—Pythonドキュメント

提供:Dev Guides
< PythonPython/docs/3.9/library/numbers
移動先:案内検索

numbers —数値の抽象基本クラス

ソースコード: :source: `Lib / numbers.py`



numbers モジュール( PEP 3141 )は、より多くの操作を段階的に定義する数値抽象基本クラスの階層を定義します。 このモジュールで定義されているタイプはいずれも、インスタンス化することを目的としていません。

class numbers.Number
数値階層のルート。 引数 x が数値かどうかを確認したいだけで、種類を気にしない場合は、isinstance(x, Number)を使用します。

数値タワー

class numbers.Complex

このタイプのサブクラスは、複素数を記述し、組み込みの complex タイプで機能する操作を含みます。 これらは、 complex および boolrealimag+-への変換です。 、*/**abs()conjugate()==、および!=-!=を除くすべてが抽象的です。

real

概要。 この数値の実数成分を取得します。

imag

概要。 この数値の虚数成分を取得します。

class numbers.Real

Complex に、 Real は実数で機能する演算を追加します。

つまり、 floatmath.trunc()round()math.floor()への変換です。 、 math.ceil()divmod()//%<<=>、および>=

Realは、 complex()realimag 、およびconjugate()のデフォルトも提供します。

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があり、それらを追加する可能性を排除した場合、これは貧弱な階層になります。 ComplexReal の間に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は、 Complexa : A <: Complex)およびb : B <: ComplexのサブタイプであるAのインスタンスになります。 a + bを検討します:

  1. Abを受け入れる__add__()を定義している場合、すべてが順調です。
  2. Aがボイラープレートコードにフォールバックし、__add__()から値を返す場合、Bがよりインテリジェントな [を定義する可能性を見逃します。 X167X]なので、ボイラープレートは__add__()から NotImplemented を返す必要があります。 (または、A__add__()をまったく実装しない場合があります。)
  3. 次に、B__radd__()がチャンスを獲得します。 aを受け入れる場合は、すべて問題ありません。
  4. ボイラープレートにフォールバックした場合、試すことができる方法はこれ以上ないため、これがデフォルトの実装が存在する場所です。
  5. B <: Aの場合、PythonはA.__add__の前にB.__radd__を試行します。 Aの知識で実装されているため、これは問題ありません。 Complex に委任する前にこれらのインスタンスを処理できます。


他の知識を共有せずにA <: ComplexB <: 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)

# ...