Skip to content

Commit 3404b3c

Browse files
committed
Check in some documentation tweaks for PEP 3141, add some tests, and implement
the promotion to complex on pow(negative, fraction).
1 parent aaaef11 commit 3404b3c

5 files changed

Lines changed: 68 additions & 33 deletions

File tree

Lib/numbers.py

Lines changed: 60 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
# Copyright 2007 Google, Inc. All Rights Reserved.
22
# Licensed to PSF under a Contributor Agreement.
33

4-
"""Abstract Base Classes (ABCs) for numbers, according to PEP 3141."""
4+
"""Abstract Base Classes (ABCs) for numbers, according to PEP 3141.
5+
6+
TODO: Fill out more detailed documentation on the operators."""
57

68
from abc import ABCMeta, abstractmethod, abstractproperty
79

@@ -56,10 +58,10 @@ class Complex(Number):
5658

5759
@abstractmethod
5860
def __complex__(self):
59-
"""Return a builtin complex instance."""
61+
"""Return a builtin complex instance. Called for complex(self)."""
6062

6163
def __bool__(self):
62-
"""True if self != 0."""
64+
"""True if self != 0. Called for bool(self)."""
6365
return self != 0
6466

6567
@abstractproperty
@@ -80,53 +82,64 @@ def imag(self):
8082

8183
@abstractmethod
8284
def __add__(self, other):
85+
"""self + other"""
8386
raise NotImplementedError
8487

8588
@abstractmethod
8689
def __radd__(self, other):
90+
"""other + self"""
8791
raise NotImplementedError
8892

8993
@abstractmethod
9094
def __neg__(self):
95+
"""-self"""
9196
raise NotImplementedError
9297

9398
def __pos__(self):
99+
"""+self"""
94100
return self
95101

96102
def __sub__(self, other):
103+
"""self - other"""
97104
return self + -other
98105

99106
def __rsub__(self, other):
107+
"""other - self"""
100108
return -self + other
101109

102110
@abstractmethod
103111
def __mul__(self, other):
112+
"""self * other"""
104113
raise NotImplementedError
105114

106115
@abstractmethod
107116
def __rmul__(self, other):
117+
"""other * self"""
108118
raise NotImplementedError
109119

110120
@abstractmethod
111121
def __div__(self, other):
122+
"""self / other"""
112123
raise NotImplementedError
113124

114125
@abstractmethod
115126
def __rdiv__(self, other):
127+
"""other / self"""
116128
raise NotImplementedError
117129

118130
@abstractmethod
119131
def __pow__(self, exponent):
120-
"""Like division, a**b should promote to complex when necessary."""
132+
"""Like division, self**exponent should promote to complex when necessary."""
121133
raise NotImplementedError
122134

123135
@abstractmethod
124136
def __rpow__(self, base):
137+
"""base ** self"""
125138
raise NotImplementedError
126139

127140
@abstractmethod
128141
def __abs__(self):
129-
"""Returns the Real distance from 0."""
142+
"""Returns the Real distance from 0. Called for abs(self)."""
130143
raise NotImplementedError
131144

132145
@abstractmethod
@@ -136,9 +149,11 @@ def conjugate(self):
136149

137150
@abstractmethod
138151
def __eq__(self, other):
152+
"""self == other"""
139153
raise NotImplementedError
140154

141155
def __ne__(self, other):
156+
"""self != other"""
142157
return not (self == other)
143158

144159
Complex.register(complex)
@@ -155,12 +170,14 @@ class Real(Complex):
155170

156171
@abstractmethod
157172
def __float__(self):
158-
"""Any Real can be converted to a native float object."""
173+
"""Any Real can be converted to a native float object.
174+
175+
Called for float(self)."""
159176
raise NotImplementedError
160177

161178
@abstractmethod
162179
def __trunc__(self):
163-
"""Truncates self to an Integral.
180+
"""trunc(self): Truncates self to an Integral.
164181
165182
Returns an Integral i such that:
166183
* i>0 iff self>0
@@ -169,15 +186,15 @@ def __trunc__(self):
169186
raise NotImplementedError
170187

171188
def __divmod__(self, other):
172-
"""The pair (self // other, self % other).
189+
"""divmod(self, other): The pair (self // other, self % other).
173190
174191
Sometimes this can be computed faster than the pair of
175192
operations.
176193
"""
177194
return (self // other, self % other)
178195

179196
def __rdivmod__(self, other):
180-
"""The pair (self // other, self % other).
197+
"""divmod(other, self): The pair (self // other, self % other).
181198
182199
Sometimes this can be computed faster than the pair of
183200
operations.
@@ -186,40 +203,49 @@ def __rdivmod__(self, other):
186203

187204
@abstractmethod
188205
def __floordiv__(self, other):
189-
"""The floor() of self/other."""
206+
"""self // other: The floor() of self/other."""
190207
raise NotImplementedError
191208

192209
@abstractmethod
193210
def __rfloordiv__(self, other):
194-
"""The floor() of other/self."""
211+
"""other // self: The floor() of other/self."""
195212
raise NotImplementedError
196213

197214
@abstractmethod
198215
def __mod__(self, other):
216+
"""self % other"""
199217
raise NotImplementedError
200218

201219
@abstractmethod
202220
def __rmod__(self, other):
221+
"""other % self"""
203222
raise NotImplementedError
204223

205224
@abstractmethod
206225
def __lt__(self, other):
207-
"""< on Reals defines a total ordering, except perhaps for NaN."""
226+
"""self < other
227+
228+
< on Reals defines a total ordering, except perhaps for NaN."""
208229
raise NotImplementedError
209230

231+
@abstractmethod
210232
def __le__(self, other):
233+
"""self <= other"""
211234
raise NotImplementedError
212235

213236
# Concrete implementations of Complex abstract methods.
214237
def __complex__(self):
238+
"""complex(self) == complex(float(self), 0)"""
215239
return complex(float(self))
216240

217241
@property
218242
def real(self):
243+
"""Real numbers are their real component."""
219244
return self
220245

221246
@property
222247
def imag(self):
248+
"""Real numbers have no imaginary component."""
223249
return 0
224250

225251
def conjugate(self):
@@ -242,6 +268,7 @@ def denominator(self):
242268

243269
# Concrete implementation of Real's conversion to float.
244270
def __float__(self):
271+
"""float(self) = self.numerator / self.denominator"""
245272
return self.numerator / self.denominator
246273

247274

@@ -250,76 +277,92 @@ class Integral(Rational):
250277

251278
@abstractmethod
252279
def __int__(self):
280+
"""int(self)"""
253281
raise NotImplementedError
254282

255283
def __index__(self):
284+
"""index(self)"""
256285
return int(self)
257286

258287
@abstractmethod
259-
def __pow__(self, exponent, modulus):
288+
def __pow__(self, exponent, modulus=None):
260289
"""self ** exponent % modulus, but maybe faster.
261290
262-
Implement this if you want to support the 3-argument version
263-
of pow(). Otherwise, just implement the 2-argument version
264-
described in Complex. Raise a TypeError if exponent < 0 or any
265-
argument isn't Integral.
291+
Accept the modulus argument if you want to support the
292+
3-argument version of pow(). Raise a TypeError if exponent < 0
293+
or any argument isn't Integral. Otherwise, just implement the
294+
2-argument version described in Complex.
266295
"""
267296
raise NotImplementedError
268297

269298
@abstractmethod
270299
def __lshift__(self, other):
300+
"""self << other"""
271301
raise NotImplementedError
272302

273303
@abstractmethod
274304
def __rlshift__(self, other):
305+
"""other << self"""
275306
raise NotImplementedError
276307

277308
@abstractmethod
278309
def __rshift__(self, other):
310+
"""self >> other"""
279311
raise NotImplementedError
280312

281313
@abstractmethod
282314
def __rrshift__(self, other):
315+
"""other >> self"""
283316
raise NotImplementedError
284317

285318
@abstractmethod
286319
def __and__(self, other):
320+
"""self & other"""
287321
raise NotImplementedError
288322

289323
@abstractmethod
290324
def __rand__(self, other):
325+
"""other & self"""
291326
raise NotImplementedError
292327

293328
@abstractmethod
294329
def __xor__(self, other):
330+
"""self ^ other"""
295331
raise NotImplementedError
296332

297333
@abstractmethod
298334
def __rxor__(self, other):
335+
"""other ^ self"""
299336
raise NotImplementedError
300337

301338
@abstractmethod
302339
def __or__(self, other):
340+
"""self | other"""
303341
raise NotImplementedError
304342

305343
@abstractmethod
306344
def __ror__(self, other):
345+
"""other | self"""
307346
raise NotImplementedError
308347

309348
@abstractmethod
310349
def __invert__(self):
350+
"""~self"""
311351
raise NotImplementedError
312352

313353
# Concrete implementations of Rational and Real abstract methods.
314354
def __float__(self):
355+
"""float(self) == float(int(self))"""
315356
return float(int(self))
316357

317358
@property
318359
def numerator(self):
360+
"""Integers are their own numerators."""
319361
return self
320362

321363
@property
322364
def denominator(self):
365+
"""Integers have a denominator of 1."""
323366
return 1
324367

325368
Integral.register(int)

Lib/test/test_builtin.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1358,11 +1358,13 @@ def test_pow(self):
13581358
else:
13591359
self.assertAlmostEqual(pow(x, y, z), 24.0)
13601360

1361+
self.assertAlmostEqual(pow(-1, 0.5), 1j)
1362+
self.assertAlmostEqual(pow(-1, 1/3), 0.5 + 0.8660254037844386j)
1363+
13611364
self.assertRaises(TypeError, pow, -1, -2, 3)
13621365
self.assertRaises(ValueError, pow, 1, 2, 0)
13631366
self.assertRaises(TypeError, pow, -1, -2, 3)
13641367
self.assertRaises(ValueError, pow, 1, 2, 0)
1365-
self.assertRaises(ValueError, pow, -342.43, 0.234)
13661368

13671369
self.assertRaises(TypeError, pow)
13681370

Lib/test/test_complex.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,6 @@
11
import unittest, os
22
from test import test_support
33

4-
import warnings
5-
warnings.filterwarnings(
6-
"ignore",
7-
category=DeprecationWarning,
8-
message=".*complex divmod.*are deprecated"
9-
)
10-
114
from random import random
125

136
# These tests ensure that complex math does the right thing
@@ -108,6 +101,7 @@ def test_mod(self):
108101
# % is no longer supported on complex numbers
109102
self.assertRaises(TypeError, (1+1j).__mod__, 0+0j)
110103
self.assertRaises(TypeError, lambda: (3.33+4.43j) % 0)
104+
self.assertRaises(TypeError, (1+1j).__mod__, 4.3j)
111105

112106
def test_divmod(self):
113107
self.assertRaises(TypeError, divmod, 1+1j, 1+0j)

Lib/test/test_descr.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,8 @@
33
from test.test_support import verify, vereq, verbose, TestFailed, TESTFN
44
from test.test_support import get_original_stdout
55
from copy import deepcopy
6-
import warnings
76
import types
87

9-
warnings.filterwarnings("ignore",
10-
r'complex divmod\(\), // and % are deprecated$',
11-
DeprecationWarning, r'(<string>|%s)$' % __name__)
12-
138
def veris(a, b):
149
if a is not b:
1510
raise TestFailed("%r is %r" % (a, b))

Objects/floatobject.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -680,9 +680,10 @@ float_pow(PyObject *v, PyObject *w, PyObject *z)
680680
* bugs so we have to figure it out ourselves.
681681
*/
682682
if (iw != floor(iw)) {
683-
PyErr_SetString(PyExc_ValueError, "negative number "
684-
"cannot be raised to a fractional power");
685-
return NULL;
683+
/* Negative numbers raised to fractional powers
684+
* become complex.
685+
*/
686+
return PyComplex_Type.tp_as_number->nb_power(v, w, z);
686687
}
687688
/* iw is an exact integer, albeit perhaps a very large one.
688689
* -1 raised to an exact integer should never be exceptional.

0 commit comments

Comments
 (0)