mirror of
https://github.com/python/cpython.git
synced 2024-11-25 19:03:49 +08:00
08976cb696
svn+ssh://pythondev@svn.python.org/python/trunk ........ r61404 | raymond.hettinger | 2008-03-15 21:02:04 +0100 (Sat, 15 Mar 2008) | 17 lines Removed Exact/Inexact after discussion with Yasskin. Unlike Scheme where exactness is implemented as taints, the Python implementation associated exactness with data types. This created inheritance issues (making an exact subclass of floats would result in the subclass having both an explicit Exact registration and an inherited Inexact registration). This was a problem for the decimal module which was designed to span both exact and inexact arithmetic. There was also a question of use cases and no examples were found where ABCs for exactness could be used to improve code. One other issue was having separate tags for both the affirmative and negative cases. This is at odds with the approach taken elsewhere in the Python (i.e. we don't have an ABC both Hashable and Unhashable). ........ r61405 | raymond.hettinger | 2008-03-15 21:37:50 +0100 (Sat, 15 Mar 2008) | 1 line Zap one more use of Exact/Inexact. ........ r61406 | neal.norwitz | 2008-03-15 23:03:18 +0100 (Sat, 15 Mar 2008) | 9 lines Add a warning for code like: assert (0, 'message') An empty tuple does not create a warning. While questionable usage: assert (), 'message' should not display a warning. Tested manually. The warning message could be improved. Feel free to update it. ........ r61407 | neal.norwitz | 2008-03-15 23:36:01 +0100 (Sat, 15 Mar 2008) | 1 line Handle memory allocation failure. Found by Adam Olsen ........
379 lines
9.9 KiB
Python
379 lines
9.9 KiB
Python
# 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 abc import ABCMeta, abstractmethod, abstractproperty
|
|
|
|
__all__ = ["Number", "Complex", "Real", "Rational", "Integral"]
|
|
|
|
class Number(metaclass=ABCMeta):
|
|
"""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).
|
|
"""
|
|
|
|
|
|
## 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.
|
|
"""
|
|
|
|
@abstractmethod
|
|
def __complex__(self):
|
|
"""Return a builtin complex instance. Called for complex(self)."""
|
|
|
|
def __bool__(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 real 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 __truediv__(self, other):
|
|
"""self / other: Should promote to float when necessary."""
|
|
raise NotImplementedError
|
|
|
|
@abstractmethod
|
|
def __rtruediv__(self, other):
|
|
"""other / self"""
|
|
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.
|
|
"""
|
|
|
|
@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
|
|
|
|
@abstractmethod
|
|
def __floor__(self):
|
|
"""Finds the greatest Integral <= self."""
|
|
raise NotImplementedError
|
|
|
|
@abstractmethod
|
|
def __ceil__(self):
|
|
"""Finds the least Integral >= self."""
|
|
raise NotImplementedError
|
|
|
|
@abstractmethod
|
|
def __round__(self, ndigits:"Integral"=None):
|
|
"""Rounds self to ndigits decimal places, defaulting to 0.
|
|
|
|
If ndigits is omitted or None, returns an Integral, otherwise
|
|
returns a Real. Rounds half toward even.
|
|
"""
|
|
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."""
|
|
|
|
@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 int and the bit-string operations."""
|
|
|
|
@abstractmethod
|
|
def __int__(self):
|
|
"""int(self)"""
|
|
raise NotImplementedError
|
|
|
|
def __index__(self):
|
|
"""index(self)"""
|
|
return int(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(int(self))"""
|
|
return float(int(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)
|