## 2012年4月9日 星期一

### [Python Std Library] Numeric and Math Modules : numbers — Numeric abstract base classes

Preface :
New in version 2.6.
numbers 模組 (PEP 3141) 定義了階層式的 abstract base classes. 首先來看在此模組最頂層的類別 :
- class numbers.Number
The root of the numeric hierarchy. If you just want to check if an argument x is a number, without caring what kind, use isinstance(x, Number).

The numeric tower :

- class numbers.Complex (複數)
Subclasses of this type describe complex numbers and include the operations that work on the built-in complex type. These are: conversions to complex and bool,realimag+-*/abs()conjugate()==, and !=. All except - and != are abstract.

- class numbers.Real (實數)
To ComplexReal adds the operations that work on real numbers.

In short, those are: a conversion to floatmath.trunc()round()math.floor()math.ceil()divmod()//%<<=>, and >=. Real also provides defaults for complex(),realimag, and conjugate().

- class numbers.Rational (有理數)
Subtypes Real and adds numerator and denominator properties, which should be in lowest terms. With these, it provides a default for float().

- class numbers.Integral (整數)
Subtypes Rational and adds a conversion to int. Provides defaults for float()numerator, and denominator, and bit-string operations: <<>>&^|~.

Notes for type implementors :

1. def __hash__(self):
2.     if self.denominator == 1:
3.         # Get integers right.
4.         return hash(self.numerator)
5.     # Expensive check, but definitely correct.
6.     if self == float(self):
7.         return hash(float(self))
8.     else:
9.         # Use tuple's hash to avoid a high collision rate on
10.         # simple fractions.
11.         return hash((self.numerator, self.denominator))
- Implementing the arithmetic operations

1. class MyIntegral(Integral):
2.
4.         if isinstance(other, MyIntegral):
8.         else:
9.             return NotImplemented
10.
12.         if isinstance(other, MyIntegral):
16.         elif isinstance(other, Integral):
17.             return int(other) + int(self)
18.         elif isinstance(other, Real):
19.             return float(other) + float(self)
20.         elif isinstance(other, Complex):
21.             return complex(other) + complex(self)
22.         else:
23.             return NotImplemented

1. If A defines an __add__() which accepts b, all is well.
2. If A falls back to the boilerplate code (For other as MyIntegral or OtherTypeIKnowAbout), and it were to return a value from __add__(), we’d miss the possibility that B defines a more intelligent __radd__(), so the boilerplate should return NotImplemented from __add__(). (Or A may not implement __add__() at all.)
3. Then B‘s __radd__() gets a chance. If it accepts a, all is well.
4. If it falls back to the boilerplate, there are no more possible methods to try, so this is where the default implementation should live.
5. If B <: A (B 繼承自 A), Python tries B.__radd__ before A.__add__. This is ok, because it was implemented with knowledge of A, so it can handle those instances before delegating to Integer.

1. def _operator_fallbacks(monomorphic_operator, fallback_operator):
2.     def forward(a, b):
3.         if isinstance(b, (intlong, Fraction)):
4.             return monomorphic_operator(a, b)
5.         elif isinstance(b, float):
6.             return fallback_operator(float(a), b)
7.         elif isinstance(b, complex):
8.             return fallback_operator(complex(a), b)
9.         else:
10.             return NotImplemented
11.     forward.__name__ = '__' + fallback_operator.__name__ + '__'
12.     forward.__doc__ = monomorphic_operator.__doc__
13.
14.     def reverse(b, a):
15.         if isinstance(a, Rational):
16.             # Includes ints.
17.             return monomorphic_operator(a, b)
18.         elif isinstance(a, numbers.Real):
19.             return fallback_operator(float(a), float(b))
20.         elif isinstance(a, numbers.Complex):
21.             return fallback_operator(complex(a), complex(b))
22.         else:
23.             return NotImplemented
24.     reverse.__name__ = '__r' + fallback_operator.__name__ + '__'
25.     reverse.__doc__ = monomorphic_operator.__doc__
26.
27.     return forward, reverse
28.
30.     """a + b"""
31.     return Fraction(a.numerator * b.denominator +
32.                     b.numerator * a.denominator,
33.                     a.denominator * b.denominator)
34.