Author: guido.van.rossum Date: Wed Aug 1 19:11:55 2007 New Revision: 56646 Modified: peps/trunk/pep-3141.txt Log: New version from Jeffrey. Cut NaN. Add __r*__ methods. Other stuff. Modified: peps/trunk/pep-3141.txt ============================================================================== --- peps/trunk/pep-3141.txt (original) +++ peps/trunk/pep-3141.txt Wed Aug 1 19:11:55 2007 @@ -45,30 +45,11 @@ We begin with a Number class to make it easy for people to be fuzzy about what kind of number they expect. This class only helps with -overloading; it doesn't provide any operations. +overloading; it doesn't provide any operations. :: - class Number(metaclass=MetaABC): pass + class Number(metaclass=ABCMeta): pass -Some types (primarily ``float``) define "Not a Number" (NaN) values -that return false for any comparison, including equality with -themselves, and are maintained through operations. That is, ``nan + x --> nan`` and ``nan == nan -> False`` Because this doesn't work well -with the Reals (which are otherwise totally ordered by ``<``), Guido -suggested we might put NaN in its own type. It is conceivable that -this can still be represented by C doubles but be included in a -different ABC at runtime. **Open issue:** Is this a good idea?:: - - class UndefinedNumber(Number): - """Implement IEEE 754 semantics.""" - def __lt__(self, other): return false - def __eq__(self, other): return false - ... - def __add__(self, other): return self - def __radd__(self, other): return self - ... - # Should we demand a conversion to float? - Most implementations of complex numbers will be hashable, but if you need to rely on that, you'll have to check it explicitly: mutable numbers are supported by this hierarchy. :: @@ -76,28 +57,36 @@ 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 !=. + 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. + 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.""" - @abstractmethod - @property + def __bool__(self): + """True if self != 0.""" + return self != 0 + + @abstractproperty def real(self): - """Retrieve the real component of this number, which should subclass Real.""" + """Retrieve the real component of this number. + + This should subclass Real. + """ raise NotImplementedError - @abstractmethod - @property + @abstractproperty def imag(self): - """Retrieve the real component of this number, which should subclass Real.""" + """Retrieve the real component of this number. + + This should subclass Real. + """ raise NotImplementedError @abstractmethod @@ -105,22 +94,48 @@ raise NotImplementedError @abstractmethod - def __sub__(self, other): + def __radd__(self, other): raise NotImplementedError @abstractmethod def __neg__(self): raise NotImplementedError + def __pos__(self): + return self + + def __sub__(self, other): + return self + -other + + def __rsub__(self, other): + return -self + other + @abstractmethod def __mul__(self, other): raise NotImplementedError @abstractmethod + def __rmul__(self, other): + raise NotImplementedError + + @abstractmethod def __div__(self, other): raise NotImplementedError @abstractmethod + def __rdiv__(self, other): + raise NotImplementedError + + @abstractmethod + def __pow__(self, exponent): + """Like division, a**b should promote to complex when necessary.""" + raise NotImplementedError + + @abstractmethod + def __rpow__(self, base): + raise NotImplementedError + + @abstractmethod def __abs__(self): """Returns the Real distance from 0.""" raise NotImplementedError @@ -140,7 +155,7 @@ The ``Real`` ABC indicates that the value is on the real line, and supports the operations of the ``float`` builtin. Real numbers are -totally ordered. (NaNs were handled above).:: +totally ordered except for NaNs (which this PEP basically ignores). :: class Real(Complex): """To Complex, Real adds the operations that work on real numbers. @@ -152,38 +167,61 @@ """ @abstractmethod - def __float__(self): - """Any Real can be converted to a native float object.""" + def __float__(self): + """Any Real can be converted to a native float object.""" raise NotImplementedError - + @abstractmethod - def __trunc__(self): - """Returns an Integral of the same sign as self whose abs is <= self's abs.""" + def __trunc__(self): + """Truncates self to an Integral. + + Returns an Integral i such that: + * i>0 iff self>0 + * abs(i) <= abs(self). + """ raise NotImplementedError def __divmod__(self, other): - """The pair (self // other, 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): + """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): """The floor() of self/other.""" raise NotImplementedError @abstractmethod + def __rfloordiv__(self, other): + """The floor() of other/self.""" + raise NotImplementedError + + @abstractmethod def __mod__(self, other): - """.""" + raise NotImplementedError + + @abstractmethod + def __rmod__(self, other): raise NotImplementedError @abstractmethod def __lt__(self, other): + """< on Reals defines a total ordering, except perhaps for NaN.""" raise NotImplementedError def __le__(self, other): - # Assume that if other is Real, it defines an ordering - # consistent with this class, or returns NotImplemented. - if isinstance(other, Real): - return not (other < self) + raise NotImplementedError # Concrete implementations of Complex abstract methods. @@ -198,25 +236,28 @@ def imag(self): return 0 + def conjugate(self): + """Conjugate is a no-op for Reals.""" + return self + There is no built-in rational type, but it's straightforward to write, -so we provide an ABC for it. *Open issue*: Add Demo/classes/Rat.py to -the stdlib?:: +so we provide an ABC for it. **Open issue**: Add Demo/classes/Rat.py +to the stdlib? :: class Rational(Real, Exact): """.numerator and .denominator should be in lowest terms.""" - @abstractmethod - @property + @abstractproperty def numerator(self): raise NotImplementedError - @abstractmethod - @property + @abstractproperty def denominator(self): raise NotImplementedError # Concrete implementation of Real's conversion to float. + def __float__(self): return self.numerator / self.denominator @@ -230,26 +271,64 @@ def __int__(self): raise NotImplementedError + def __index__(self): + return int(self) + + @abstractmethod + def __pow__(self, exponent, modulus): + """self ** exponent % modulus, but maybe faster. + + Implement this if you want to support the 3-argument version + of pow(). Otherwise, just implement the 2-argument version + described in Complex. Raise a TypeError if exponent < 0 or any + argument isn't Integral. + """ + raise NotImplementedError + @abstractmethod def __lshift__(self, other): raise NotImplementedError @abstractmethod + def __rlshift__(self, other): + raise NotImplementedError + + @abstractmethod def __rshift__(self, other): raise NotImplementedError @abstractmethod + def __rrshift__(self, other): + raise NotImplementedError + + @abstractmethod def __and__(self, other): raise NotImplementedError @abstractmethod + def __rand__(self, other): + raise NotImplementedError + + @abstractmethod def __xor__(self, other): raise NotImplementedError @abstractmethod + def __rxor__(self, other): + raise NotImplementedError + + @abstractmethod def __or__(self, other): raise NotImplementedError + @abstractmethod + def __ror__(self, other): + raise NotImplementedError + + @abstractmethod + def __invert__(self): + raise NotImplementedError + # Concrete implementations of Rational and Real abstract methods. def __float__(self): @@ -277,12 +356,51 @@ types have this problem. Every instance of ``Integral`` and ``Rational`` should be Exact, but ``Reals`` and ``Complexes`` may or may not be. (Do we really only need one of these, and the other is -defined as ``not`` the first?):: +defined as ``not`` the first?) :: class Exact(Number): pass class Inexact(Number): pass +Changes to operations and __magic__ methods +------------------------------------------- + +To support more precise narrowing from float to int (and more +generally, from Real to Integral), I'm proposing the following new +__magic__ methods, to be called from the corresponding library +functions. All of these return Integrals rather than Reals. + +1. ``__trunc__(self)``, called from a new builtin ``trunc(x)``, which + returns the Integral closest to ``x`` between 0 and ``x``. + +2. ``__floor__(self)``, called from ``math.floor(x)``, which returns + the greatest Integral ``<= x``. + +3. ``__ceil__(self)``, called from ``math.ceil(x)``, which returns the + least Integral ``>= x``. + +4. ``__round__(self)``, called from ``round(x)``, with returns the + Integral closest to ``x``, rounding half toward even. We could + support the 2-argument version, but then we'd only return an + Integral if the second argument were ``<= 0``. + +5. ``__properfraction__(self)``, called from a new function, + ``math.properfraction(x)``, which resembles C's ``modf()``: returns + a pair ``(n:Integral, r:Real)`` where ``x == n + r``, both ``n`` + and ``r`` have the same sign as ``x``, and ``abs(r) < 1``. **Open + issue:** Oh, we already have ``math.modf``. Do we want to keep the + bad name? + +Because the ``int()`` conversion from ``float`` is equivalent to but +less explicit than ``trunc()``, let's remove it. + +``complex.__{divmod,mod,floordiv,int,float}__`` should also go +away. These should continue to raise ``TypeError`` to help confused +porters, but should not appear in ``help(complex)`` to avoid confusing +more people. **Open issue:** This is difficult to do with the +``PyNumberMethods`` struct. What's the best way to accomplish it? + + Notes for type implementors --------------------------- @@ -298,7 +416,7 @@ complex's range or precision. Adding More Numeric ABCs ------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~ There are, of course, more possible ABCs for numbers, and this would be a poor hierarchy if it precluded the possibility of adding @@ -308,7 +426,7 @@ MyFoo.register(Real) Implementing the arithmetic operations --------------------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ We want to implement the arithmetic operations so that mixed-mode operations either call an implementation whose author knew about the
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4