# Copyright 2007 Google, Inc. All Rights Reserved. | |
# Licensed to PSF under a Contributor Agreement. | |
"""Abstract Base Classes (ABCs) for numbers, according to PEP 3141. | |
TODO: Fill out more detailed documentation on the operators.""" | |
from __future__ import division | |
from abc import ABCMeta, abstractmethod, abstractproperty | |
__all__ = ["Number", "Complex", "Real", "Rational", "Integral"] | |
class Number(object): | |
"""All numbers inherit from this class. | |
If you just want to check if an argument x is a number, without | |
caring what kind, use isinstance(x, Number). | |
""" | |
__metaclass__ = ABCMeta | |
__slots__ = () | |
# Concrete numeric types must provide their own hash implementation | |
__hash__ = None | |
## Notes on Decimal | |
## ---------------- | |
## Decimal has all of the methods specified by the Real abc, but it should | |
## not be registered as a Real because decimals do not interoperate with | |
## binary floats (i.e. Decimal('3.14') + 2.71828 is undefined). But, | |
## abstract reals are expected to interoperate (i.e. R1 + R2 should be | |
## expected to work if R1 and R2 are both Reals). | |
class Complex(Number): | |
"""Complex defines the operations that work on the builtin complex type. | |
In short, those are: a conversion to complex, .real, .imag, +, -, | |
*, /, abs(), .conjugate, ==, and !=. | |
If it is given heterogenous arguments, and doesn't have special | |
knowledge about them, it should fall back to the builtin complex | |
type as described below. | |
""" | |
__slots__ = () | |
@abstractmethod | |
def __complex__(self): | |
"""Return a builtin complex instance. Called for complex(self).""" | |
# Will be __bool__ in 3.0. | |
def __nonzero__(self): | |
"""True if self != 0. Called for bool(self).""" | |
return self != 0 | |
@abstractproperty | |
def real(self): | |
"""Retrieve the real component of this number. | |
This should subclass Real. | |
""" | |
raise NotImplementedError | |
@abstractproperty | |
def imag(self): | |
"""Retrieve the imaginary component of this number. | |
This should subclass Real. | |
""" | |
raise NotImplementedError | |
@abstractmethod | |
def __add__(self, other): | |
"""self + other""" | |
raise NotImplementedError | |
@abstractmethod | |
def __radd__(self, other): | |
"""other + self""" | |
raise NotImplementedError | |
@abstractmethod | |
def __neg__(self): | |
"""-self""" | |
raise NotImplementedError | |
@abstractmethod | |
def __pos__(self): | |
"""+self""" | |
raise NotImplementedError | |
def __sub__(self, other): | |
"""self - other""" | |
return self + -other | |
def __rsub__(self, other): | |
"""other - self""" | |
return -self + other | |
@abstractmethod | |
def __mul__(self, other): | |
"""self * other""" | |
raise NotImplementedError | |
@abstractmethod | |
def __rmul__(self, other): | |
"""other * self""" | |
raise NotImplementedError | |
@abstractmethod | |
def __div__(self, other): | |
"""self / other without __future__ division | |
May promote to float. | |
""" | |
raise NotImplementedError | |
@abstractmethod | |
def __rdiv__(self, other): | |
"""other / self without __future__ division""" | |
raise NotImplementedError | |
@abstractmethod | |
def __truediv__(self, other): | |
"""self / other with __future__ division. | |
Should promote to float when necessary. | |
""" | |
raise NotImplementedError | |
@abstractmethod | |
def __rtruediv__(self, other): | |
"""other / self with __future__ division""" | |
raise NotImplementedError | |
@abstractmethod | |
def __pow__(self, exponent): | |
"""self**exponent; should promote to float or complex when necessary.""" | |
raise NotImplementedError | |
@abstractmethod | |
def __rpow__(self, base): | |
"""base ** self""" | |
raise NotImplementedError | |
@abstractmethod | |
def __abs__(self): | |
"""Returns the Real distance from 0. Called for abs(self).""" | |
raise NotImplementedError | |
@abstractmethod | |
def conjugate(self): | |
"""(x+y*i).conjugate() returns (x-y*i).""" | |
raise NotImplementedError | |
@abstractmethod | |
def __eq__(self, other): | |
"""self == other""" | |
raise NotImplementedError | |
def __ne__(self, other): | |
"""self != other""" | |
# The default __ne__ doesn't negate __eq__ until 3.0. | |
return not (self == other) | |
Complex.register(complex) | |
class Real(Complex): | |
"""To Complex, Real adds the operations that work on real numbers. | |
In short, those are: a conversion to float, trunc(), divmod, | |
%, <, <=, >, and >=. | |
Real also provides defaults for the derived operations. | |
""" | |
__slots__ = () | |
@abstractmethod | |
def __float__(self): | |
"""Any Real can be converted to a native float object. | |
Called for float(self).""" | |
raise NotImplementedError | |
@abstractmethod | |
def __trunc__(self): | |
"""trunc(self): Truncates self to an Integral. | |
Returns an Integral i such that: | |
* i>0 iff self>0; | |
* abs(i) <= abs(self); | |
* for any Integral j satisfying the first two conditions, | |
abs(i) >= abs(j) [i.e. i has "maximal" abs among those]. | |
i.e. "truncate towards 0". | |
""" | |
raise NotImplementedError | |
def __divmod__(self, other): | |
"""divmod(self, other): The pair (self // other, self % other). | |
Sometimes this can be computed faster than the pair of | |
operations. | |
""" | |
return (self // other, self % other) | |
def __rdivmod__(self, other): | |
"""divmod(other, self): The pair (self // other, self % other). | |
Sometimes this can be computed faster than the pair of | |
operations. | |
""" | |
return (other // self, other % self) | |
@abstractmethod | |
def __floordiv__(self, other): | |
"""self // other: The floor() of self/other.""" | |
raise NotImplementedError | |
@abstractmethod | |
def __rfloordiv__(self, other): | |
"""other // self: The floor() of other/self.""" | |
raise NotImplementedError | |
@abstractmethod | |
def __mod__(self, other): | |
"""self % other""" | |
raise NotImplementedError | |
@abstractmethod | |
def __rmod__(self, other): | |
"""other % self""" | |
raise NotImplementedError | |
@abstractmethod | |
def __lt__(self, other): | |
"""self < other | |
< on Reals defines a total ordering, except perhaps for NaN.""" | |
raise NotImplementedError | |
@abstractmethod | |
def __le__(self, other): | |
"""self <= other""" | |
raise NotImplementedError | |
# Concrete implementations of Complex abstract methods. | |
def __complex__(self): | |
"""complex(self) == complex(float(self), 0)""" | |
return complex(float(self)) | |
@property | |
def real(self): | |
"""Real numbers are their real component.""" | |
return +self | |
@property | |
def imag(self): | |
"""Real numbers have no imaginary component.""" | |
return 0 | |
def conjugate(self): | |
"""Conjugate is a no-op for Reals.""" | |
return +self | |
Real.register(float) | |
class Rational(Real): | |
""".numerator and .denominator should be in lowest terms.""" | |
__slots__ = () | |
@abstractproperty | |
def numerator(self): | |
raise NotImplementedError | |
@abstractproperty | |
def denominator(self): | |
raise NotImplementedError | |
# Concrete implementation of Real's conversion to float. | |
def __float__(self): | |
"""float(self) = self.numerator / self.denominator | |
It's important that this conversion use the integer's "true" | |
division rather than casting one side to float before dividing | |
so that ratios of huge integers convert without overflowing. | |
""" | |
return self.numerator / self.denominator | |
class Integral(Rational): | |
"""Integral adds a conversion to long and the bit-string operations.""" | |
__slots__ = () | |
@abstractmethod | |
def __long__(self): | |
"""long(self)""" | |
raise NotImplementedError | |
def __index__(self): | |
"""index(self)""" | |
return long(self) | |
@abstractmethod | |
def __pow__(self, exponent, modulus=None): | |
"""self ** exponent % modulus, but maybe faster. | |
Accept the modulus argument if you want to support the | |
3-argument version of pow(). Raise a TypeError if exponent < 0 | |
or any argument isn't Integral. Otherwise, just implement the | |
2-argument version described in Complex. | |
""" | |
raise NotImplementedError | |
@abstractmethod | |
def __lshift__(self, other): | |
"""self << other""" | |
raise NotImplementedError | |
@abstractmethod | |
def __rlshift__(self, other): | |
"""other << self""" | |
raise NotImplementedError | |
@abstractmethod | |
def __rshift__(self, other): | |
"""self >> other""" | |
raise NotImplementedError | |
@abstractmethod | |
def __rrshift__(self, other): | |
"""other >> self""" | |
raise NotImplementedError | |
@abstractmethod | |
def __and__(self, other): | |
"""self & other""" | |
raise NotImplementedError | |
@abstractmethod | |
def __rand__(self, other): | |
"""other & self""" | |
raise NotImplementedError | |
@abstractmethod | |
def __xor__(self, other): | |
"""self ^ other""" | |
raise NotImplementedError | |
@abstractmethod | |
def __rxor__(self, other): | |
"""other ^ self""" | |
raise NotImplementedError | |
@abstractmethod | |
def __or__(self, other): | |
"""self | other""" | |
raise NotImplementedError | |
@abstractmethod | |
def __ror__(self, other): | |
"""other | self""" | |
raise NotImplementedError | |
@abstractmethod | |
def __invert__(self): | |
"""~self""" | |
raise NotImplementedError | |
# Concrete implementations of Rational and Real abstract methods. | |
def __float__(self): | |
"""float(self) == float(long(self))""" | |
return float(long(self)) | |
@property | |
def numerator(self): | |
"""Integers are their own numerators.""" | |
return +self | |
@property | |
def denominator(self): | |
"""Integers have a denominator of 1.""" | |
return 1 | |
Integral.register(int) | |
Integral.register(long) |