[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