[Python-checkins] r56646 - peps/trunk/pep-3141.txt

guido.van.rossum python-checkins at python.org
Wed Aug 1 19:11:57 CEST 2007


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


More information about the Python-checkins mailing list