• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 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
6TODO: Fill out more detailed documentation on the operators."""
7
8from abc import ABCMeta, abstractmethod
9
10__all__ = ["Number", "Complex", "Real", "Rational", "Integral"]
11
12class Number(metaclass=ABCMeta):
13    """All numbers inherit from this class.
14
15    If you just want to check if an argument x is a number, without
16    caring what kind, use isinstance(x, Number).
17    """
18    __slots__ = ()
19
20    # Concrete numeric types must provide their own hash implementation
21    __hash__ = None
22
23
24## Notes on Decimal
25## ----------------
26## Decimal has all of the methods specified by the Real abc, but it should
27## not be registered as a Real because decimals do not interoperate with
28## binary floats (i.e.  Decimal('3.14') + 2.71828 is undefined).  But,
29## abstract reals are expected to interoperate (i.e. R1 + R2 should be
30## expected to work if R1 and R2 are both Reals).
31
32class Complex(Number):
33    """Complex defines the operations that work on the builtin complex type.
34
35    In short, those are: a conversion to complex, .real, .imag, +, -,
36    *, /, **, abs(), .conjugate, ==, and !=.
37
38    If it is given heterogeneous arguments, and doesn't have special
39    knowledge about them, it should fall back to the builtin complex
40    type as described below.
41    """
42
43    __slots__ = ()
44
45    @abstractmethod
46    def __complex__(self):
47        """Return a builtin complex instance. Called for complex(self)."""
48
49    def __bool__(self):
50        """True if self != 0. Called for bool(self)."""
51        return self != 0
52
53    @property
54    @abstractmethod
55    def real(self):
56        """Retrieve the real component of this number.
57
58        This should subclass Real.
59        """
60        raise NotImplementedError
61
62    @property
63    @abstractmethod
64    def imag(self):
65        """Retrieve the imaginary component of this number.
66
67        This should subclass Real.
68        """
69        raise NotImplementedError
70
71    @abstractmethod
72    def __add__(self, other):
73        """self + other"""
74        raise NotImplementedError
75
76    @abstractmethod
77    def __radd__(self, other):
78        """other + self"""
79        raise NotImplementedError
80
81    @abstractmethod
82    def __neg__(self):
83        """-self"""
84        raise NotImplementedError
85
86    @abstractmethod
87    def __pos__(self):
88        """+self"""
89        raise NotImplementedError
90
91    def __sub__(self, other):
92        """self - other"""
93        return self + -other
94
95    def __rsub__(self, other):
96        """other - self"""
97        return -self + other
98
99    @abstractmethod
100    def __mul__(self, other):
101        """self * other"""
102        raise NotImplementedError
103
104    @abstractmethod
105    def __rmul__(self, other):
106        """other * self"""
107        raise NotImplementedError
108
109    @abstractmethod
110    def __truediv__(self, other):
111        """self / other: Should promote to float when necessary."""
112        raise NotImplementedError
113
114    @abstractmethod
115    def __rtruediv__(self, other):
116        """other / self"""
117        raise NotImplementedError
118
119    @abstractmethod
120    def __pow__(self, exponent):
121        """self**exponent; should promote to float or complex when necessary."""
122        raise NotImplementedError
123
124    @abstractmethod
125    def __rpow__(self, base):
126        """base ** self"""
127        raise NotImplementedError
128
129    @abstractmethod
130    def __abs__(self):
131        """Returns the Real distance from 0. Called for abs(self)."""
132        raise NotImplementedError
133
134    @abstractmethod
135    def conjugate(self):
136        """(x+y*i).conjugate() returns (x-y*i)."""
137        raise NotImplementedError
138
139    @abstractmethod
140    def __eq__(self, other):
141        """self == other"""
142        raise NotImplementedError
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    __slots__ = ()
157
158    @abstractmethod
159    def __float__(self):
160        """Any Real can be converted to a native float object.
161
162        Called for float(self)."""
163        raise NotImplementedError
164
165    @abstractmethod
166    def __trunc__(self):
167        """trunc(self): Truncates self to an Integral.
168
169        Returns an Integral i such that:
170          * i>0 iff self>0;
171          * abs(i) <= abs(self);
172          * for any Integral j satisfying the first two conditions,
173            abs(i) >= abs(j) [i.e. i has "maximal" abs among those].
174        i.e. "truncate towards 0".
175        """
176        raise NotImplementedError
177
178    @abstractmethod
179    def __floor__(self):
180        """Finds the greatest Integral <= self."""
181        raise NotImplementedError
182
183    @abstractmethod
184    def __ceil__(self):
185        """Finds the least Integral >= self."""
186        raise NotImplementedError
187
188    @abstractmethod
189    def __round__(self, ndigits=None):
190        """Rounds self to ndigits decimal places, defaulting to 0.
191
192        If ndigits is omitted or None, returns an Integral, otherwise
193        returns a Real. Rounds half toward even.
194        """
195        raise NotImplementedError
196
197    def __divmod__(self, other):
198        """divmod(self, other): The pair (self // other, self % other).
199
200        Sometimes this can be computed faster than the pair of
201        operations.
202        """
203        return (self // other, self % other)
204
205    def __rdivmod__(self, other):
206        """divmod(other, self): The pair (self // other, self % other).
207
208        Sometimes this can be computed faster than the pair of
209        operations.
210        """
211        return (other // self, other % self)
212
213    @abstractmethod
214    def __floordiv__(self, other):
215        """self // other: The floor() of self/other."""
216        raise NotImplementedError
217
218    @abstractmethod
219    def __rfloordiv__(self, other):
220        """other // self: The floor() of other/self."""
221        raise NotImplementedError
222
223    @abstractmethod
224    def __mod__(self, other):
225        """self % other"""
226        raise NotImplementedError
227
228    @abstractmethod
229    def __rmod__(self, other):
230        """other % self"""
231        raise NotImplementedError
232
233    @abstractmethod
234    def __lt__(self, other):
235        """self < other
236
237        < on Reals defines a total ordering, except perhaps for NaN."""
238        raise NotImplementedError
239
240    @abstractmethod
241    def __le__(self, other):
242        """self <= other"""
243        raise NotImplementedError
244
245    # Concrete implementations of Complex abstract methods.
246    def __complex__(self):
247        """complex(self) == complex(float(self), 0)"""
248        return complex(float(self))
249
250    @property
251    def real(self):
252        """Real numbers are their real component."""
253        return +self
254
255    @property
256    def imag(self):
257        """Real numbers have no imaginary component."""
258        return 0
259
260    def conjugate(self):
261        """Conjugate is a no-op for Reals."""
262        return +self
263
264Real.register(float)
265
266
267class Rational(Real):
268    """.numerator and .denominator should be in lowest terms."""
269
270    __slots__ = ()
271
272    @property
273    @abstractmethod
274    def numerator(self):
275        raise NotImplementedError
276
277    @property
278    @abstractmethod
279    def denominator(self):
280        raise NotImplementedError
281
282    # Concrete implementation of Real's conversion to float.
283    def __float__(self):
284        """float(self) = self.numerator / self.denominator
285
286        It's important that this conversion use the integer's "true"
287        division rather than casting one side to float before dividing
288        so that ratios of huge integers convert without overflowing.
289
290        """
291        return self.numerator / self.denominator
292
293
294class Integral(Rational):
295    """Integral adds methods that work on integral numbers.
296
297    In short, these are conversion to int, pow with modulus, and the
298    bit-string operations.
299    """
300
301    __slots__ = ()
302
303    @abstractmethod
304    def __int__(self):
305        """int(self)"""
306        raise NotImplementedError
307
308    def __index__(self):
309        """Called whenever an index is needed, such as in slicing"""
310        return int(self)
311
312    @abstractmethod
313    def __pow__(self, exponent, modulus=None):
314        """self ** exponent % modulus, but maybe faster.
315
316        Accept the modulus argument if you want to support the
317        3-argument version of pow(). Raise a TypeError if exponent < 0
318        or any argument isn't Integral. Otherwise, just implement the
319        2-argument version described in Complex.
320        """
321        raise NotImplementedError
322
323    @abstractmethod
324    def __lshift__(self, other):
325        """self << other"""
326        raise NotImplementedError
327
328    @abstractmethod
329    def __rlshift__(self, other):
330        """other << self"""
331        raise NotImplementedError
332
333    @abstractmethod
334    def __rshift__(self, other):
335        """self >> other"""
336        raise NotImplementedError
337
338    @abstractmethod
339    def __rrshift__(self, other):
340        """other >> self"""
341        raise NotImplementedError
342
343    @abstractmethod
344    def __and__(self, other):
345        """self & other"""
346        raise NotImplementedError
347
348    @abstractmethod
349    def __rand__(self, other):
350        """other & self"""
351        raise NotImplementedError
352
353    @abstractmethod
354    def __xor__(self, other):
355        """self ^ other"""
356        raise NotImplementedError
357
358    @abstractmethod
359    def __rxor__(self, other):
360        """other ^ self"""
361        raise NotImplementedError
362
363    @abstractmethod
364    def __or__(self, other):
365        """self | other"""
366        raise NotImplementedError
367
368    @abstractmethod
369    def __ror__(self, other):
370        """other | self"""
371        raise NotImplementedError
372
373    @abstractmethod
374    def __invert__(self):
375        """~self"""
376        raise NotImplementedError
377
378    # Concrete implementations of Rational and Real abstract methods.
379    def __float__(self):
380        """float(self) == float(int(self))"""
381        return float(int(self))
382
383    @property
384    def numerator(self):
385        """Integers are their own numerators."""
386        return +self
387
388    @property
389    def denominator(self):
390        """Integers have a denominator of 1."""
391        return 1
392
393Integral.register(int)
394