mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
Check in some documentation tweaks for PEP 3141, add some tests, and implement
the promotion to complex on pow(negative, fraction).
This commit is contained in:
parent
aaaef110dc
commit
3404b3ce2a
5 changed files with 68 additions and 33 deletions
|
@ -1,7 +1,9 @@
|
||||||
# Copyright 2007 Google, Inc. All Rights Reserved.
|
# Copyright 2007 Google, Inc. All Rights Reserved.
|
||||||
# Licensed to PSF under a Contributor Agreement.
|
# 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
|
from abc import ABCMeta, abstractmethod, abstractproperty
|
||||||
|
|
||||||
|
@ -56,10 +58,10 @@ class Complex(Number):
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def __complex__(self):
|
def __complex__(self):
|
||||||
"""Return a builtin complex instance."""
|
"""Return a builtin complex instance. Called for complex(self)."""
|
||||||
|
|
||||||
def __bool__(self):
|
def __bool__(self):
|
||||||
"""True if self != 0."""
|
"""True if self != 0. Called for bool(self)."""
|
||||||
return self != 0
|
return self != 0
|
||||||
|
|
||||||
@abstractproperty
|
@abstractproperty
|
||||||
|
@ -80,53 +82,64 @@ class Complex(Number):
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def __add__(self, other):
|
def __add__(self, other):
|
||||||
|
"""self + other"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def __radd__(self, other):
|
def __radd__(self, other):
|
||||||
|
"""other + self"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def __neg__(self):
|
def __neg__(self):
|
||||||
|
"""-self"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def __pos__(self):
|
def __pos__(self):
|
||||||
|
"""+self"""
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __sub__(self, other):
|
def __sub__(self, other):
|
||||||
|
"""self - other"""
|
||||||
return self + -other
|
return self + -other
|
||||||
|
|
||||||
def __rsub__(self, other):
|
def __rsub__(self, other):
|
||||||
|
"""other - self"""
|
||||||
return -self + other
|
return -self + other
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def __mul__(self, other):
|
def __mul__(self, other):
|
||||||
|
"""self * other"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def __rmul__(self, other):
|
def __rmul__(self, other):
|
||||||
|
"""other * self"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def __div__(self, other):
|
def __div__(self, other):
|
||||||
|
"""self / other"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def __rdiv__(self, other):
|
def __rdiv__(self, other):
|
||||||
|
"""other / self"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def __pow__(self, exponent):
|
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
|
raise NotImplementedError
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def __rpow__(self, base):
|
def __rpow__(self, base):
|
||||||
|
"""base ** self"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def __abs__(self):
|
def __abs__(self):
|
||||||
"""Returns the Real distance from 0."""
|
"""Returns the Real distance from 0. Called for abs(self)."""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
|
@ -136,9 +149,11 @@ class Complex(Number):
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
|
"""self == other"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def __ne__(self, other):
|
def __ne__(self, other):
|
||||||
|
"""self != other"""
|
||||||
return not (self == other)
|
return not (self == other)
|
||||||
|
|
||||||
Complex.register(complex)
|
Complex.register(complex)
|
||||||
|
@ -155,12 +170,14 @@ class Real(Complex):
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def __float__(self):
|
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
|
raise NotImplementedError
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def __trunc__(self):
|
def __trunc__(self):
|
||||||
"""Truncates self to an Integral.
|
"""trunc(self): Truncates self to an Integral.
|
||||||
|
|
||||||
Returns an Integral i such that:
|
Returns an Integral i such that:
|
||||||
* i>0 iff self>0
|
* i>0 iff self>0
|
||||||
|
@ -169,7 +186,7 @@ class Real(Complex):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def __divmod__(self, other):
|
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
|
Sometimes this can be computed faster than the pair of
|
||||||
operations.
|
operations.
|
||||||
|
@ -177,7 +194,7 @@ class Real(Complex):
|
||||||
return (self // other, self % other)
|
return (self // other, self % other)
|
||||||
|
|
||||||
def __rdivmod__(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
|
Sometimes this can be computed faster than the pair of
|
||||||
operations.
|
operations.
|
||||||
|
@ -186,40 +203,49 @@ class Real(Complex):
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def __floordiv__(self, other):
|
def __floordiv__(self, other):
|
||||||
"""The floor() of self/other."""
|
"""self // other: The floor() of self/other."""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def __rfloordiv__(self, other):
|
def __rfloordiv__(self, other):
|
||||||
"""The floor() of other/self."""
|
"""other // self: The floor() of other/self."""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def __mod__(self, other):
|
def __mod__(self, other):
|
||||||
|
"""self % other"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def __rmod__(self, other):
|
def __rmod__(self, other):
|
||||||
|
"""other % self"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def __lt__(self, other):
|
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
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
def __le__(self, other):
|
def __le__(self, other):
|
||||||
|
"""self <= other"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
# Concrete implementations of Complex abstract methods.
|
# Concrete implementations of Complex abstract methods.
|
||||||
def __complex__(self):
|
def __complex__(self):
|
||||||
|
"""complex(self) == complex(float(self), 0)"""
|
||||||
return complex(float(self))
|
return complex(float(self))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def real(self):
|
def real(self):
|
||||||
|
"""Real numbers are their real component."""
|
||||||
return self
|
return self
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def imag(self):
|
def imag(self):
|
||||||
|
"""Real numbers have no imaginary component."""
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def conjugate(self):
|
def conjugate(self):
|
||||||
|
@ -242,6 +268,7 @@ class Rational(Real, Exact):
|
||||||
|
|
||||||
# Concrete implementation of Real's conversion to float.
|
# Concrete implementation of Real's conversion to float.
|
||||||
def __float__(self):
|
def __float__(self):
|
||||||
|
"""float(self) = self.numerator / self.denominator"""
|
||||||
return self.numerator / self.denominator
|
return self.numerator / self.denominator
|
||||||
|
|
||||||
|
|
||||||
|
@ -250,76 +277,92 @@ class Integral(Rational):
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def __int__(self):
|
def __int__(self):
|
||||||
|
"""int(self)"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def __index__(self):
|
def __index__(self):
|
||||||
|
"""index(self)"""
|
||||||
return int(self)
|
return int(self)
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def __pow__(self, exponent, modulus):
|
def __pow__(self, exponent, modulus=None):
|
||||||
"""self ** exponent % modulus, but maybe faster.
|
"""self ** exponent % modulus, but maybe faster.
|
||||||
|
|
||||||
Implement this if you want to support the 3-argument version
|
Accept the modulus argument if you want to support the
|
||||||
of pow(). Otherwise, just implement the 2-argument version
|
3-argument version of pow(). Raise a TypeError if exponent < 0
|
||||||
described in Complex. Raise a TypeError if exponent < 0 or any
|
or any argument isn't Integral. Otherwise, just implement the
|
||||||
argument isn't Integral.
|
2-argument version described in Complex.
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def __lshift__(self, other):
|
def __lshift__(self, other):
|
||||||
|
"""self << other"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def __rlshift__(self, other):
|
def __rlshift__(self, other):
|
||||||
|
"""other << self"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def __rshift__(self, other):
|
def __rshift__(self, other):
|
||||||
|
"""self >> other"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def __rrshift__(self, other):
|
def __rrshift__(self, other):
|
||||||
|
"""other >> self"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def __and__(self, other):
|
def __and__(self, other):
|
||||||
|
"""self & other"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def __rand__(self, other):
|
def __rand__(self, other):
|
||||||
|
"""other & self"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def __xor__(self, other):
|
def __xor__(self, other):
|
||||||
|
"""self ^ other"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def __rxor__(self, other):
|
def __rxor__(self, other):
|
||||||
|
"""other ^ self"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def __or__(self, other):
|
def __or__(self, other):
|
||||||
|
"""self | other"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def __ror__(self, other):
|
def __ror__(self, other):
|
||||||
|
"""other | self"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def __invert__(self):
|
def __invert__(self):
|
||||||
|
"""~self"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
# Concrete implementations of Rational and Real abstract methods.
|
# Concrete implementations of Rational and Real abstract methods.
|
||||||
def __float__(self):
|
def __float__(self):
|
||||||
|
"""float(self) == float(int(self))"""
|
||||||
return float(int(self))
|
return float(int(self))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def numerator(self):
|
def numerator(self):
|
||||||
|
"""Integers are their own numerators."""
|
||||||
return self
|
return self
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def denominator(self):
|
def denominator(self):
|
||||||
|
"""Integers have a denominator of 1."""
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
Integral.register(int)
|
Integral.register(int)
|
||||||
|
|
|
@ -1358,11 +1358,13 @@ class BuiltinTest(unittest.TestCase):
|
||||||
else:
|
else:
|
||||||
self.assertAlmostEqual(pow(x, y, z), 24.0)
|
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(TypeError, pow, -1, -2, 3)
|
||||||
self.assertRaises(ValueError, pow, 1, 2, 0)
|
self.assertRaises(ValueError, pow, 1, 2, 0)
|
||||||
self.assertRaises(TypeError, pow, -1, -2, 3)
|
self.assertRaises(TypeError, pow, -1, -2, 3)
|
||||||
self.assertRaises(ValueError, pow, 1, 2, 0)
|
self.assertRaises(ValueError, pow, 1, 2, 0)
|
||||||
self.assertRaises(ValueError, pow, -342.43, 0.234)
|
|
||||||
|
|
||||||
self.assertRaises(TypeError, pow)
|
self.assertRaises(TypeError, pow)
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,6 @@
|
||||||
import unittest, os
|
import unittest, os
|
||||||
from test import test_support
|
from test import test_support
|
||||||
|
|
||||||
import warnings
|
|
||||||
warnings.filterwarnings(
|
|
||||||
"ignore",
|
|
||||||
category=DeprecationWarning,
|
|
||||||
message=".*complex divmod.*are deprecated"
|
|
||||||
)
|
|
||||||
|
|
||||||
from random import random
|
from random import random
|
||||||
|
|
||||||
# These tests ensure that complex math does the right thing
|
# 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
|
# % is no longer supported on complex numbers
|
||||||
self.assertRaises(TypeError, (1+1j).__mod__, 0+0j)
|
self.assertRaises(TypeError, (1+1j).__mod__, 0+0j)
|
||||||
self.assertRaises(TypeError, lambda: (3.33+4.43j) % 0)
|
self.assertRaises(TypeError, lambda: (3.33+4.43j) % 0)
|
||||||
|
self.assertRaises(TypeError, (1+1j).__mod__, 4.3j)
|
||||||
|
|
||||||
def test_divmod(self):
|
def test_divmod(self):
|
||||||
self.assertRaises(TypeError, divmod, 1+1j, 1+0j)
|
self.assertRaises(TypeError, divmod, 1+1j, 1+0j)
|
||||||
|
|
|
@ -3,13 +3,8 @@
|
||||||
from test.test_support import verify, vereq, verbose, TestFailed, TESTFN
|
from test.test_support import verify, vereq, verbose, TestFailed, TESTFN
|
||||||
from test.test_support import get_original_stdout
|
from test.test_support import get_original_stdout
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
import warnings
|
|
||||||
import types
|
import types
|
||||||
|
|
||||||
warnings.filterwarnings("ignore",
|
|
||||||
r'complex divmod\(\), // and % are deprecated$',
|
|
||||||
DeprecationWarning, r'(<string>|%s)$' % __name__)
|
|
||||||
|
|
||||||
def veris(a, b):
|
def veris(a, b):
|
||||||
if a is not b:
|
if a is not b:
|
||||||
raise TestFailed("%r is %r" % (a, b))
|
raise TestFailed("%r is %r" % (a, b))
|
||||||
|
|
|
@ -680,9 +680,10 @@ float_pow(PyObject *v, PyObject *w, PyObject *z)
|
||||||
* bugs so we have to figure it out ourselves.
|
* bugs so we have to figure it out ourselves.
|
||||||
*/
|
*/
|
||||||
if (iw != floor(iw)) {
|
if (iw != floor(iw)) {
|
||||||
PyErr_SetString(PyExc_ValueError, "negative number "
|
/* Negative numbers raised to fractional powers
|
||||||
"cannot be raised to a fractional power");
|
* become complex.
|
||||||
return NULL;
|
*/
|
||||||
|
return PyComplex_Type.tp_as_number->nb_power(v, w, z);
|
||||||
}
|
}
|
||||||
/* iw is an exact integer, albeit perhaps a very large one.
|
/* iw is an exact integer, albeit perhaps a very large one.
|
||||||
* -1 raised to an exact integer should never be exceptional.
|
* -1 raised to an exact integer should never be exceptional.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue