# `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

  相對於 `Complex`，`Real` 加入了只有實數才能進行的操作。

  簡單的說，有 `float` 的轉換、`math.trunc()`、`round()`、`math.floor()`、`math.ceil()`、`divmod()`、`//`、`%`、 `<`、`<=`、`>`、和 `>=`。

  實數同樣提供 `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()` 方法增加了求餘 (modulus) 和位元字串運算 (bit-string operations) 的抽象方法：`<<`、`>>`、`&`、`^`、`|`、`~`。

## 給型別實作者的註記

實作者需注意，相等的數值除了大小相等外，還必須擁有同樣的雜湊值。當使用兩個不同的實數擴充時，這可能是很微妙的。例如，`fractions.Fraction` 底下的 `hash()` 實作如下：

    def __hash__(self):
        if self.denominator == 1:
            # 正確處理整數。
            return hash(self.numerator)
        # 檢查費時，但絕對正確。
        if self == float(self):
            return hash(float(self))
        else:
            # 使用 tuple 的雜湊值以避免簡單分數上的高碰撞率。
            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` 的程式碼稱作「模板 (boilerplate)」。`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, 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):
                # 包含整數。
                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)

    # ...