"numbers" --- 数の抽象基底クラス
********************************

**ソースコード:** 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

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

   abstractmethod conjugate()

      抽象メソッド。 複素共役を返します。 たとえば、
      "(1+3j).conjugate() == (1-3j)" です。

class numbers.Real

   "Real" は "Complex" に実数の演算を追加します。

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

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

class numbers.Rational

   "Real" をサブタイプ化し "numerator" と "denominator" のプロパティを
   加えたものです。これは "float()" のデフォルトも提供します。

   "numerator" と "denominator" の値は "Integral" のインスタンスでなけ
   ればならず、 "denominator" が正の既約分数になっていなければなりませ
   ん。

   numerator

      抽象プロパティ。 この有理数の分子。

   denominator

      抽象プロパティ。 この有理数の分母。

class numbers.Integral

   "Rational" をサブタイプ化し "int" への変換が加わります。 "float()",
   "numerator", "denominator" のデフォルトを提供します。法 (訳注: 割る
   数、除数のこと) を持つ "pow()" に対する抽象メソッドと、ビット列演算
   "<<", ">>", "&", "^", "|", "~" を追加します。


型を実装する人向けの注意事項
============================

実装するときは、等しい数が等しいと比較され、同じハッシュ値を持つよう注
意してください。 実数を異なる方法で拡張した型が 2 つある場合、この扱い
は難しいことがあります。 数値型のハッシュ化 も参照してください。


さらに数のABCを追加する
-----------------------

数に対する ABC が他にも多く存在しうることは、言うまでもありません。そ
れらの ABC を階層に追加する可能性が閉ざされるとしたら、その階層は貧相
な階層でしかありません。たとえば、 "MyFoo" を "Complex" と "Real" の間
に付け加えるには、次のようにします:

   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

ここには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" となります。

ある型の演算の多くは似た形になるので、演算子ごとに通常の演算と反射演算
のメソッドを生成するヘルパー関数を定義すると便利です。 例えば
"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):
               # int も含みます。
               return monomorphic_operator(a, b)
           elif isinstance(a, Real):
               return fallback_operator(float(a), float(b))
           elif isinstance(a, 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)

   # ...
