blob: 8678a3a04581263fa844a4c60a1a5a4b5d5f803f [file] [log] [blame]
Guido van Rossum1daf9542007-08-30 17:45:54 +00001# Copyright 2007 Google, Inc. All Rights Reserved.
2# Licensed to PSF under a Contributor Agreement.
3
4"""Abstract Base Classes (ABCs) for numbers, according to PEP 3141."""
5
6from abc import ABCMeta, abstractmethod, abstractproperty
7
8__all__ = ["Number", "Exact", "Inexact",
9 "Complex", "Real", "Rational", "Integral",
10 ]
11
12
13class Number(metaclass=ABCMeta):
14 """All numbers inherit from this class.
15
16 If you just want to check if an argument x is a number, without
17 caring what kind, use isinstance(x, Number).
18 """
19
20
21class Exact(Number):
22 """Operations on instances of this type are exact.
23
24 As long as the result of a homogenous operation is of the same
25 type, you can assume that it was computed exactly, and there are
26 no round-off errors. Laws like commutativity and associativity
27 hold.
28 """
29
30Exact.register(int)
31
32
33class Inexact(Number):
34 """Operations on instances of this type are inexact.
35
36 Given X, an instance of Inexact, it is possible that (X + -X) + 3
37 == 3, but X + (-X + 3) == 0. The exact form this error takes will
38 vary by type, but it's generally unsafe to compare this type for
39 equality.
40 """
41
42Inexact.register(complex)
43Inexact.register(float)
44
45
46class Complex(Number):
47 """Complex defines the operations that work on the builtin complex type.
48
49 In short, those are: a conversion to complex, .real, .imag, +, -,
50 *, /, abs(), .conjugate, ==, and !=.
51
52 If it is given heterogenous arguments, and doesn't have special
53 knowledge about them, it should fall back to the builtin complex
54 type as described below.
55 """
56
57 @abstractmethod
58 def __complex__(self):
59 """Return a builtin complex instance."""
60
61 def __bool__(self):
62 """True if self != 0."""
63 return self != 0
64
65 @abstractproperty
66 def real(self):
67 """Retrieve the real component of this number.
68
69 This should subclass Real.
70 """
71 raise NotImplementedError
72
73 @abstractproperty
74 def imag(self):
75 """Retrieve the real component of this number.
76
77 This should subclass Real.
78 """
79 raise NotImplementedError
80
81 @abstractmethod
82 def __add__(self, other):
83 raise NotImplementedError
84
85 @abstractmethod
86 def __radd__(self, other):
87 raise NotImplementedError
88
89 @abstractmethod
90 def __neg__(self):
91 raise NotImplementedError
92
93 def __pos__(self):
94 return self
95
96 def __sub__(self, other):
97 return self + -other
98
99 def __rsub__(self, other):
100 return -self + other
101
102 @abstractmethod
103 def __mul__(self, other):
104 raise NotImplementedError
105
106 @abstractmethod
107 def __rmul__(self, other):
108 raise NotImplementedError
109
110 @abstractmethod
111 def __div__(self, other):
112 raise NotImplementedError
113
114 @abstractmethod
115 def __rdiv__(self, other):
116 raise NotImplementedError
117
118 @abstractmethod
119 def __pow__(self, exponent):
120 """Like division, a**b should promote to complex when necessary."""
121 raise NotImplementedError
122
123 @abstractmethod
124 def __rpow__(self, base):
125 raise NotImplementedError
126
127 @abstractmethod
128 def __abs__(self):
129 """Returns the Real distance from 0."""
130 raise NotImplementedError
131
132 @abstractmethod
133 def conjugate(self):
134 """(x+y*i).conjugate() returns (x-y*i)."""
135 raise NotImplementedError
136
137 @abstractmethod
138 def __eq__(self, other):
139 raise NotImplementedError
140
141 def __ne__(self, other):
142 return not (self == other)
143
144Complex.register(complex)
145
146
147class Real(Complex):
148 """To Complex, Real adds the operations that work on real numbers.
149
150 In short, those are: a conversion to float, trunc(), divmod,
151 %, <, <=, >, and >=.
152
153 Real also provides defaults for the derived operations.
154 """
155
156 @abstractmethod
157 def __float__(self):
158 """Any Real can be converted to a native float object."""
159 raise NotImplementedError
160
161 @abstractmethod
162 def __trunc__(self):
163 """Truncates self to an Integral.
164
165 Returns an Integral i such that:
166 * i>0 iff self>0
167 * abs(i) <= abs(self).
168 """
169 raise NotImplementedError
170
171 def __divmod__(self, other):
172 """The pair (self // other, self % other).
173
174 Sometimes this can be computed faster than the pair of
175 operations.
176 """
177 return (self // other, self % other)
178
179 def __rdivmod__(self, other):
180 """The pair (self // other, self % other).
181
182 Sometimes this can be computed faster than the pair of
183 operations.
184 """
185 return (other // self, other % self)
186
187 @abstractmethod
188 def __floordiv__(self, other):
189 """The floor() of self/other."""
190 raise NotImplementedError
191
192 @abstractmethod
193 def __rfloordiv__(self, other):
194 """The floor() of other/self."""
195 raise NotImplementedError
196
197 @abstractmethod
198 def __mod__(self, other):
199 raise NotImplementedError
200
201 @abstractmethod
202 def __rmod__(self, other):
203 raise NotImplementedError
204
205 @abstractmethod
206 def __lt__(self, other):
207 """< on Reals defines a total ordering, except perhaps for NaN."""
208 raise NotImplementedError
209
210 def __le__(self, other):
211 raise NotImplementedError
212
213 # Concrete implementations of Complex abstract methods.
214 def __complex__(self):
215 return complex(float(self))
216
217 @property
218 def real(self):
219 return self
220
221 @property
222 def imag(self):
223 return 0
224
225 def conjugate(self):
226 """Conjugate is a no-op for Reals."""
227 return self
228
229Real.register(float)
230
231
232class Rational(Real, Exact):
233 """.numerator and .denominator should be in lowest terms."""
234
235 @abstractproperty
236 def numerator(self):
237 raise NotImplementedError
238
239 @abstractproperty
240 def denominator(self):
241 raise NotImplementedError
242
243 # Concrete implementation of Real's conversion to float.
244 def __float__(self):
245 return self.numerator / self.denominator
246
247
248class Integral(Rational):
249 """Integral adds a conversion to int and the bit-string operations."""
250
251 @abstractmethod
252 def __int__(self):
253 raise NotImplementedError
254
255 def __index__(self):
256 return int(self)
257
258 @abstractmethod
259 def __pow__(self, exponent, modulus):
260 """self ** exponent % modulus, but maybe faster.
261
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.
266 """
267 raise NotImplementedError
268
269 @abstractmethod
270 def __lshift__(self, other):
271 raise NotImplementedError
272
273 @abstractmethod
274 def __rlshift__(self, other):
275 raise NotImplementedError
276
277 @abstractmethod
278 def __rshift__(self, other):
279 raise NotImplementedError
280
281 @abstractmethod
282 def __rrshift__(self, other):
283 raise NotImplementedError
284
285 @abstractmethod
286 def __and__(self, other):
287 raise NotImplementedError
288
289 @abstractmethod
290 def __rand__(self, other):
291 raise NotImplementedError
292
293 @abstractmethod
294 def __xor__(self, other):
295 raise NotImplementedError
296
297 @abstractmethod
298 def __rxor__(self, other):
299 raise NotImplementedError
300
301 @abstractmethod
302 def __or__(self, other):
303 raise NotImplementedError
304
305 @abstractmethod
306 def __ror__(self, other):
307 raise NotImplementedError
308
309 @abstractmethod
310 def __invert__(self):
311 raise NotImplementedError
312
313 # Concrete implementations of Rational and Real abstract methods.
314 def __float__(self):
315 return float(int(self))
316
317 @property
318 def numerator(self):
319 return self
320
321 @property
322 def denominator(self):
323 return 1
324
325Integral.register(int)