Home | History | Annotate | Download | only in Lib
      1 # Copyright 2007 Google, Inc. All Rights Reserved.
      2 # Licensed to PSF under a Contributor Agreement.
      3 
      4 """Abstract Base Classes (ABCs) for numbers, according to PEP 3141.
      5 
      6 TODO: Fill out more detailed documentation on the operators."""
      7 
      8 from abc import ABCMeta, abstractmethod
      9 
     10 __all__ = ["Number", "Complex", "Real", "Rational", "Integral"]
     11 
     12 class Number(metaclass=ABCMeta):
     13     """All numbers inherit from this class.
     14 
     15     If you just want to check if an argument x is a number, without
     16     caring what kind, use isinstance(x, Number).
     17     """
     18     __slots__ = ()
     19 
     20     # Concrete numeric types must provide their own hash implementation
     21     __hash__ = None
     22 
     23 
     24 ## Notes on Decimal
     25 ## ----------------
     26 ## Decimal has all of the methods specified by the Real abc, but it should
     27 ## not be registered as a Real because decimals do not interoperate with
     28 ## binary floats (i.e.  Decimal('3.14') + 2.71828 is undefined).  But,
     29 ## abstract reals are expected to interoperate (i.e. R1 + R2 should be
     30 ## expected to work if R1 and R2 are both Reals).
     31 
     32 class Complex(Number):
     33     """Complex defines the operations that work on the builtin complex type.
     34 
     35     In short, those are: a conversion to complex, .real, .imag, +, -,
     36     *, /, abs(), .conjugate, ==, and !=.
     37 
     38     If it is given heterogenous arguments, and doesn't have special
     39     knowledge about them, it should fall back to the builtin complex
     40     type as described below.
     41     """
     42 
     43     __slots__ = ()
     44 
     45     @abstractmethod
     46     def __complex__(self):
     47         """Return a builtin complex instance. Called for complex(self)."""
     48 
     49     def __bool__(self):
     50         """True if self != 0. Called for bool(self)."""
     51         return self != 0
     52 
     53     @property
     54     @abstractmethod
     55     def real(self):
     56         """Retrieve the real component of this number.
     57 
     58         This should subclass Real.
     59         """
     60         raise NotImplementedError
     61 
     62     @property
     63     @abstractmethod
     64     def imag(self):
     65         """Retrieve the imaginary component of this number.
     66 
     67         This should subclass Real.
     68         """
     69         raise NotImplementedError
     70 
     71     @abstractmethod
     72     def __add__(self, other):
     73         """self + other"""
     74         raise NotImplementedError
     75 
     76     @abstractmethod
     77     def __radd__(self, other):
     78         """other + self"""
     79         raise NotImplementedError
     80 
     81     @abstractmethod
     82     def __neg__(self):
     83         """-self"""
     84         raise NotImplementedError
     85 
     86     @abstractmethod
     87     def __pos__(self):
     88         """+self"""
     89         raise NotImplementedError
     90 
     91     def __sub__(self, other):
     92         """self - other"""
     93         return self + -other
     94 
     95     def __rsub__(self, other):
     96         """other - self"""
     97         return -self + other
     98 
     99     @abstractmethod
    100     def __mul__(self, other):
    101         """self * other"""
    102         raise NotImplementedError
    103 
    104     @abstractmethod
    105     def __rmul__(self, other):
    106         """other * self"""
    107         raise NotImplementedError
    108 
    109     @abstractmethod
    110     def __truediv__(self, other):
    111         """self / other: Should promote to float when necessary."""
    112         raise NotImplementedError
    113 
    114     @abstractmethod
    115     def __rtruediv__(self, other):
    116         """other / self"""
    117         raise NotImplementedError
    118 
    119     @abstractmethod
    120     def __pow__(self, exponent):
    121         """self**exponent; should promote to float or complex when necessary."""
    122         raise NotImplementedError
    123 
    124     @abstractmethod
    125     def __rpow__(self, base):
    126         """base ** self"""
    127         raise NotImplementedError
    128 
    129     @abstractmethod
    130     def __abs__(self):
    131         """Returns the Real distance from 0. Called for abs(self)."""
    132         raise NotImplementedError
    133 
    134     @abstractmethod
    135     def conjugate(self):
    136         """(x+y*i).conjugate() returns (x-y*i)."""
    137         raise NotImplementedError
    138 
    139     @abstractmethod
    140     def __eq__(self, other):
    141         """self == other"""
    142         raise NotImplementedError
    143 
    144 Complex.register(complex)
    145 
    146 
    147 class Real(Complex):
    148     """To Complex, Real adds the operations that work on real numbers.
    149 
    150     In short, those are: a conversion to float, trunc(), divmod,
    151     %, <, <=, >, and >=.
    152 
    153     Real also provides defaults for the derived operations.
    154     """
    155 
    156     __slots__ = ()
    157 
    158     @abstractmethod
    159     def __float__(self):
    160         """Any Real can be converted to a native float object.
    161 
    162         Called for float(self)."""
    163         raise NotImplementedError
    164 
    165     @abstractmethod
    166     def __trunc__(self):
    167         """trunc(self): Truncates self to an Integral.
    168 
    169         Returns an Integral i such that:
    170           * i>0 iff self>0;
    171           * abs(i) <= abs(self);
    172           * for any Integral j satisfying the first two conditions,
    173             abs(i) >= abs(j) [i.e. i has "maximal" abs among those].
    174         i.e. "truncate towards 0".
    175         """
    176         raise NotImplementedError
    177 
    178     @abstractmethod
    179     def __floor__(self):
    180         """Finds the greatest Integral <= self."""
    181         raise NotImplementedError
    182 
    183     @abstractmethod
    184     def __ceil__(self):
    185         """Finds the least Integral >= self."""
    186         raise NotImplementedError
    187 
    188     @abstractmethod
    189     def __round__(self, ndigits=None):
    190         """Rounds self to ndigits decimal places, defaulting to 0.
    191 
    192         If ndigits is omitted or None, returns an Integral, otherwise
    193         returns a Real. Rounds half toward even.
    194         """
    195         raise NotImplementedError
    196 
    197     def __divmod__(self, other):
    198         """divmod(self, other): The pair (self // other, self % other).
    199 
    200         Sometimes this can be computed faster than the pair of
    201         operations.
    202         """
    203         return (self // other, self % other)
    204 
    205     def __rdivmod__(self, other):
    206         """divmod(other, self): The pair (self // other, self % other).
    207 
    208         Sometimes this can be computed faster than the pair of
    209         operations.
    210         """
    211         return (other // self, other % self)
    212 
    213     @abstractmethod
    214     def __floordiv__(self, other):
    215         """self // other: The floor() of self/other."""
    216         raise NotImplementedError
    217 
    218     @abstractmethod
    219     def __rfloordiv__(self, other):
    220         """other // self: The floor() of other/self."""
    221         raise NotImplementedError
    222 
    223     @abstractmethod
    224     def __mod__(self, other):
    225         """self % other"""
    226         raise NotImplementedError
    227 
    228     @abstractmethod
    229     def __rmod__(self, other):
    230         """other % self"""
    231         raise NotImplementedError
    232 
    233     @abstractmethod
    234     def __lt__(self, other):
    235         """self < other
    236 
    237         < on Reals defines a total ordering, except perhaps for NaN."""
    238         raise NotImplementedError
    239 
    240     @abstractmethod
    241     def __le__(self, other):
    242         """self <= other"""
    243         raise NotImplementedError
    244 
    245     # Concrete implementations of Complex abstract methods.
    246     def __complex__(self):
    247         """complex(self) == complex(float(self), 0)"""
    248         return complex(float(self))
    249 
    250     @property
    251     def real(self):
    252         """Real numbers are their real component."""
    253         return +self
    254 
    255     @property
    256     def imag(self):
    257         """Real numbers have no imaginary component."""
    258         return 0
    259 
    260     def conjugate(self):
    261         """Conjugate is a no-op for Reals."""
    262         return +self
    263 
    264 Real.register(float)
    265 
    266 
    267 class Rational(Real):
    268     """.numerator and .denominator should be in lowest terms."""
    269 
    270     __slots__ = ()
    271 
    272     @property
    273     @abstractmethod
    274     def numerator(self):
    275         raise NotImplementedError
    276 
    277     @property
    278     @abstractmethod
    279     def denominator(self):
    280         raise NotImplementedError
    281 
    282     # Concrete implementation of Real's conversion to float.
    283     def __float__(self):
    284         """float(self) = self.numerator / self.denominator
    285 
    286         It's important that this conversion use the integer's "true"
    287         division rather than casting one side to float before dividing
    288         so that ratios of huge integers convert without overflowing.
    289 
    290         """
    291         return self.numerator / self.denominator
    292 
    293 
    294 class Integral(Rational):
    295     """Integral adds a conversion to int and the bit-string operations."""
    296 
    297     __slots__ = ()
    298 
    299     @abstractmethod
    300     def __int__(self):
    301         """int(self)"""
    302         raise NotImplementedError
    303 
    304     def __index__(self):
    305         """Called whenever an index is needed, such as in slicing"""
    306         return int(self)
    307 
    308     @abstractmethod
    309     def __pow__(self, exponent, modulus=None):
    310         """self ** exponent % modulus, but maybe faster.
    311 
    312         Accept the modulus argument if you want to support the
    313         3-argument version of pow(). Raise a TypeError if exponent < 0
    314         or any argument isn't Integral. Otherwise, just implement the
    315         2-argument version described in Complex.
    316         """
    317         raise NotImplementedError
    318 
    319     @abstractmethod
    320     def __lshift__(self, other):
    321         """self << other"""
    322         raise NotImplementedError
    323 
    324     @abstractmethod
    325     def __rlshift__(self, other):
    326         """other << self"""
    327         raise NotImplementedError
    328 
    329     @abstractmethod
    330     def __rshift__(self, other):
    331         """self >> other"""
    332         raise NotImplementedError
    333 
    334     @abstractmethod
    335     def __rrshift__(self, other):
    336         """other >> self"""
    337         raise NotImplementedError
    338 
    339     @abstractmethod
    340     def __and__(self, other):
    341         """self & other"""
    342         raise NotImplementedError
    343 
    344     @abstractmethod
    345     def __rand__(self, other):
    346         """other & self"""
    347         raise NotImplementedError
    348 
    349     @abstractmethod
    350     def __xor__(self, other):
    351         """self ^ other"""
    352         raise NotImplementedError
    353 
    354     @abstractmethod
    355     def __rxor__(self, other):
    356         """other ^ self"""
    357         raise NotImplementedError
    358 
    359     @abstractmethod
    360     def __or__(self, other):
    361         """self | other"""
    362         raise NotImplementedError
    363 
    364     @abstractmethod
    365     def __ror__(self, other):
    366         """other | self"""
    367         raise NotImplementedError
    368 
    369     @abstractmethod
    370     def __invert__(self):
    371         """~self"""
    372         raise NotImplementedError
    373 
    374     # Concrete implementations of Rational and Real abstract methods.
    375     def __float__(self):
    376         """float(self) == float(int(self))"""
    377         return float(int(self))
    378 
    379     @property
    380     def numerator(self):
    381         """Integers are their own numerators."""
    382         return +self
    383 
    384     @property
    385     def denominator(self):
    386         """Integers have a denominator of 1."""
    387         return 1
    388 
    389 Integral.register(int)
    390