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