9.1. numbers — 数の抽象基底クラス — Python 2.7ja1 documentation

### ナビゲーション

- 索引
- モジュール |
- 次へ |
- 前へ |
- Python 2.7ja1 documentation »
- Python 標準ライブラリ »
- 9. 数値と数学モジュール »

# 9.1. `numbers` — 数の抽象基底クラス

バージョン 2.6 で追加.

`numbers` モジュール (PEP 3141) は数の抽象基底クラスの、順により多くの演算を定義していく階層を定義します。このモジュールで定義される型はどれもインスタンス化できません。

class `numbers.` `Number`

  数の階層の根。引数 x が、種類は何であれ、数であるということだけチェックしたい場合、 `isinstance(x, Number)` が使えます。

## 9.1.1. 数値塔

class `numbers.` `Complex`

  この型のサブクラスは複素数を表し、組み込みの `complex` 型を受け付ける演算を含みます。それらは: `complex` および `bool` への変換、 `real`, `imag`, `+`, `-`, `*`, `/`, `abs()`, `conjugate()`, `==`, `!=` です。 `-` と `!=` 以外の全てのものは抽象メソッドや抽象プロパティです。

  `real`

    抽象プロパティ。この複素数の実数部分を取り出します。

  `imag`

    抽象プロパティ。この複素数の虚数部分を取り出します。

  `conjugate`()

    抽象プロパティ。複素共役を返します。たとえば、 `(1+3j).conjugate() == (1-3j)` です。

class `numbers.` `Real`

  `Complex` の上に、 `Real` は実数で意味を成す演算を加えます。

  簡潔に言うとそれらは: `float` への変換, `math.trunc()`, `round()`, `math.floor()`, `math.ceil()`, `divmod()`, `//`, `%`, `<`, `<=`, `>` および `>=` です。

  Real はまた `complex()`, `real`, `imag` および `conjugate()` のデフォルトを提供します。

class `numbers.` `Rational`

  `Real` をサブタイプ化し `numerator` と `denominator` のプロパティを加えたものです。これら分子分母は最小の値でなければなりません。この他に `float()` のデフォルトも提供します。

  `numerator`

    抽象プロパティ。

  `denominator`

    抽象プロパティ。

class `numbers.` `Integral`

  `Rational` をサブタイプ化し `int` への変換が加わります。 `float()`, `numerator` および `denominator` のデフォルトと、ビット列演算: `<<`, `>>`, `&`, `^`, `|`, `~` を提供します。

## 9.1.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))

### 9.1.2.1. さらに数のABCを追加する

もちろん、他にも数に対する ABC が有り得ますし、そういったものを付け加える可能性を閉ざしてしまうとすれば貧相な階層でしかありません。たとえば `MyFoo` を `Complex` と `Real` の間に付け加えるには:

    class MyFoo(Complex): ...
    MyFoo.register(Real)

### 9.1.2.2. 算術演算の実装

私たちは、混在型(mixed-mode)演算について作者が両方の引数の型について知っているような実装を呼び出すか、両方を最も近い組み込み型に変換してそこで演算するか、どちらかを行うように算術演算を実装したいのです。 `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

ここには5つの異なる `Complex` のサブクラス間の混在型の演算があります。上のコードの中で `MyIntegral` と `OtherTypeIKnowAbout` に触れない部分を “ボイラープレート” と呼ぶことにしましょう。 `a` を `Complex` のサブタイプである `A` のインスタンス (`a : A <: Complex`)、同様に `b : B <: Complex` として、 `a + b` を考えます:

> 1. `A` が `b` を受け付ける `__add__()` を定義している場合、何も問題はありません。
> 2. `A` でボイラープレート部分に落ち込み、その結果 `__add__()` が値を返すならば、 `B` に良く考えられた `__radd__()` が定義されている可能性を見逃してしまいますので、ボイラープレートは `__add__()` から `NotImplemented` を返すのが良いでしょう。(若しくは、 `A` はまったく `__add__()` を実装すべきではなかったかもしれません。)
> 3. そうすると、 `B` の `__radd__()` にチャンスが巡ってきます。ここで `a` が受け付けられるならば、結果は上々です。
> 4. ここでボイラープレートに落ち込むならば、もう他に試すべきメソッドはありませんので、デフォルト実装の出番です。
> 5. もし `B <: A` ならば、Python は `A.__add__` の前に `B.__radd__` を試します。これで良い理由は、 `A` についての知識を持って実装しており、 `Complex` に委ねる前にこれらのインスタンスを扱えるはずだからです。

もし `A <: Complex` かつ `B <: Real` で他に共有された知識が無いならば、適切な共通の演算は組み込みの `complex` を使ったものになり、どちらの `__radd__()` ともそこに着地するでしょうから、 `a+b == b+a` です。

ほとんどの演算はどのような型についても非常に良く似ていますので、与えられた演算子について順結合(forward)および逆結合(reverse)のメソッドを生成する支援関数を定義することは役に立ちます。たとえば、 `fractions.Fraction` では次のようなものを利用しています:

    def _operator_fallbacks(monomorphic_operator, fallback_operator):
        def forward(a, b):
            if isinstance(b, (int, long, 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)

    # ...

### ナビゲーション

- 索引
- モジュール |
- 次へ |
- 前へ |
- Python 2.7ja1 documentation »
- Python 標準ライブラリ »
- 9. 数値と数学モジュール »