summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/numbers.py77
-rw-r--r--Lib/test/test_builtin.py4
-rw-r--r--Lib/test/test_complex.py8
-rw-r--r--Lib/test/test_descr.py5
-rw-r--r--Objects/floatobject.c7
5 files changed, 68 insertions, 33 deletions
diff --git a/Lib/numbers.py b/Lib/numbers.py
index 8678a3a..34cc803 100644
--- a/Lib/numbers.py
+++ b/Lib/numbers.py
@@ -1,7 +1,9 @@
# Copyright 2007 Google, Inc. All Rights Reserved.
# Licensed to PSF under a Contributor Agreement.
-"""Abstract Base Classes (ABCs) for numbers, according to PEP 3141."""
+"""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
@@ -56,10 +58,10 @@ class Complex(Number):
@abstractmethod
def __complex__(self):
- """Return a builtin complex instance."""
+ """Return a builtin complex instance. Called for complex(self)."""
def __bool__(self):
- """True if self != 0."""
+ """True if self != 0. Called for bool(self)."""
return self != 0
@abstractproperty
@@ -80,53 +82,64 @@ class Complex(Number):
@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
def __pos__(self):
+ """+self"""
return self
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"""
raise NotImplementedError
@abstractmethod
def __rdiv__(self, other):
+ """other / self"""
raise NotImplementedError
@abstractmethod
def __pow__(self, exponent):
- """Like division, a**b should promote to complex when necessary."""
+ """Like division, self**exponent should promote to complex when necessary."""
raise NotImplementedError
@abstractmethod
def __rpow__(self, base):
+ """base ** self"""
raise NotImplementedError
@abstractmethod
def __abs__(self):
- """Returns the Real distance from 0."""
+ """Returns the Real distance from 0. Called for abs(self)."""
raise NotImplementedError
@abstractmethod
@@ -136,9 +149,11 @@ class Complex(Number):
@abstractmethod
def __eq__(self, other):
+ """self == other"""
raise NotImplementedError
def __ne__(self, other):
+ """self != other"""
return not (self == other)
Complex.register(complex)
@@ -155,12 +170,14 @@ class Real(Complex):
@abstractmethod
def __float__(self):
- """Any Real can be converted to a native float object."""
+ """Any Real can be converted to a native float object.
+
+ Called for float(self)."""
raise NotImplementedError
@abstractmethod
def __trunc__(self):
- """Truncates self to an Integral.
+ """trunc(self): Truncates self to an Integral.
Returns an Integral i such that:
* i>0 iff self>0
@@ -169,7 +186,7 @@ class Real(Complex):
raise NotImplementedError
def __divmod__(self, other):
- """The pair (self // other, self % other).
+ """divmod(self, other): The pair (self // other, self % other).
Sometimes this can be computed faster than the pair of
operations.
@@ -177,7 +194,7 @@ class Real(Complex):
return (self // other, self % other)
def __rdivmod__(self, other):
- """The pair (self // other, self % other).
+ """divmod(other, self): The pair (self // other, self % other).
Sometimes this can be computed faster than the pair of
operations.
@@ -186,40 +203,49 @@ class Real(Complex):
@abstractmethod
def __floordiv__(self, other):
- """The floor() of self/other."""
+ """self // other: The floor() of self/other."""
raise NotImplementedError
@abstractmethod
def __rfloordiv__(self, other):
- """The floor() of other/self."""
+ """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):
- """< on Reals defines a total ordering, except perhaps for NaN."""
+ """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):
@@ -242,6 +268,7 @@ class Rational(Real, Exact):
# Concrete implementation of Real's conversion to float.
def __float__(self):
+ """float(self) = self.numerator / self.denominator"""
return self.numerator / self.denominator
@@ -250,76 +277,92 @@ class Integral(Rational):
@abstractmethod
def __int__(self):
+ """int(self)"""
raise NotImplementedError
def __index__(self):
+ """index(self)"""
return int(self)
@abstractmethod
- def __pow__(self, exponent, modulus):
+ def __pow__(self, exponent, modulus=None):
"""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.
+ 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)
diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py
index d9633af..b6b45ee 100644
--- a/Lib/test/test_builtin.py
+++ b/Lib/test/test_builtin.py
@@ -1358,11 +1358,13 @@ class BuiltinTest(unittest.TestCase):
else:
self.assertAlmostEqual(pow(x, y, z), 24.0)
+ self.assertAlmostEqual(pow(-1, 0.5), 1j)
+ self.assertAlmostEqual(pow(-1, 1/3), 0.5 + 0.8660254037844386j)
+
self.assertRaises(TypeError, pow, -1, -2, 3)
self.assertRaises(ValueError, pow, 1, 2, 0)
self.assertRaises(TypeError, pow, -1, -2, 3)
self.assertRaises(ValueError, pow, 1, 2, 0)
- self.assertRaises(ValueError, pow, -342.43, 0.234)
self.assertRaises(TypeError, pow)
diff --git a/Lib/test/test_complex.py b/Lib/test/test_complex.py
index b4082d9..5397ad6 100644
--- a/Lib/test/test_complex.py
+++ b/Lib/test/test_complex.py
@@ -1,13 +1,6 @@
import unittest, os
from test import test_support
-import warnings
-warnings.filterwarnings(
- "ignore",
- category=DeprecationWarning,
- message=".*complex divmod.*are deprecated"
-)
-
from random import random
# These tests ensure that complex math does the right thing
@@ -108,6 +101,7 @@ class ComplexTest(unittest.TestCase):
# % is no longer supported on complex numbers
self.assertRaises(TypeError, (1+1j).__mod__, 0+0j)
self.assertRaises(TypeError, lambda: (3.33+4.43j) % 0)
+ self.assertRaises(TypeError, (1+1j).__mod__, 4.3j)
def test_divmod(self):
self.assertRaises(TypeError, divmod, 1+1j, 1+0j)
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py
index 47b647c..bfa6a64 100644
--- a/Lib/test/test_descr.py
+++ b/Lib/test/test_descr.py
@@ -3,13 +3,8 @@
from test.test_support import verify, vereq, verbose, TestFailed, TESTFN
from test.test_support import get_original_stdout
from copy import deepcopy
-import warnings
import types
-warnings.filterwarnings("ignore",
- r'complex divmod\(\), // and % are deprecated$',
- DeprecationWarning, r'(<string>|%s)$' % __name__)
-
def veris(a, b):
if a is not b:
raise TestFailed("%r is %r" % (a, b))
diff --git a/Objects/floatobject.c b/Objects/floatobject.c
index 7c489d9..eb540e6 100644
--- a/Objects/floatobject.c
+++ b/Objects/floatobject.c
@@ -680,9 +680,10 @@ float_pow(PyObject *v, PyObject *w, PyObject *z)
* bugs so we have to figure it out ourselves.
*/
if (iw != floor(iw)) {
- PyErr_SetString(PyExc_ValueError, "negative number "
- "cannot be raised to a fractional power");
- return NULL;
+ /* Negative numbers raised to fractional powers
+ * become complex.
+ */
+ return PyComplex_Type.tp_as_number->nb_power(v, w, z);
}
/* iw is an exact integer, albeit perhaps a very large one.
* -1 raised to an exact integer should never be exceptional.