int/long unification hides bugs

Andrew Dalke adalke at mindspring.com
Wed Oct 27 02:45:16 EDT 2004


Bengt Richter wrote:
> If you are willing to make your variables exist in an object's attribute
> name space, you can define almost any behavior you want.

Or, here's another solution -- make a number-like object which
handles range checking for every operation.


The big problem here is that unlike Ada, C++, or other languages
that let you declare variable types, I have to figure out how
to merge the allowed ranges of the two values during a binary op.
I decided to use the intersection.  Unlike Pythons ranges, I
choose low <= val <= high (as compared to low <= val < high).

import sys

class RangedNumber:
     def __init__(self, val, low = -sys.maxint-1, high = sys.maxint):
         if not (low <= high):
             raise ValueError("low(= %r) > high(= %r)" % (low, high))
         if not (low <= val <= high):
             raise ValueError("value %r not in range %r to %r" %
                              (val, low, high))
         self.val = val
         self.low = low
         self.high = high

     def __str__(self):
         return str(self.val)
     def __repr__(self):
         return "RangedNumber(%r, %r, %r)" % (self.val, self.low, self.high)

     def __int__(self):
         return self.val
     def __float__(self):
         return self.val

     def _get_range(self, other):
         if isinstance(other, RangedNumber):
             low = max(self.low, other.low)
             high = min(self.high, other.high)
             other_val = other.val
         else:
             low = self.low
             high = self.high
             other_val = other

         return other_val, low, high

     def __add__(self, other):
         other_val, low, high = self._get_range(other)
         x = self.val + other_val
         return RangedNumber(x, low, high)

     def __radd__(self, other):
         other_val, low, high = self._get_range(other)
         x = other_val + self.val
         return RangedNumber(x, low, high)

     def __sub__(self, other):
         other_val, low, high = self._get_range(other)
         x = self.val - other_val
         return RangedNumber(x, low, high)

     def __rsub__(self, other):
         other_val, low, high = self._get_range(other)
         x = other_val - self.val
         return RangedNumber(x, low, high)

     def __abs__(self):
         return RangedNumber(abs(self.val), self.low, self.high)

     def __mul__(self, other):
         other_val, low, high = self._get_range(other)
         x = self.val * other_val
         return RangedNumber(x, low, high)

     def __rmul__(self, other):
         other_val, low, high = self._get_range(other)
         x = other_val * self.val
         return RangedNumber(x, low, high)

     # ... and many, many more ...

Here's some code using it


 >>> a = RangedNumber(10, 0, 100)
 >>>
 >>> a
RangedNumber(10, 0, 100)
 >>> print a
10
 >>> a+90
RangedNumber(100, 0, 100)
 >>> a+91
Traceback (most recent call last):
   File "<stdin>", line 1, in ?
   File "spam.py", line 39, in __add__
     return RangedNumber(x, low, high)
   File "spam.py", line 8, in __init__
     raise ValueError("value %r not in range %r to %r" %
ValueError: value 101 not in range 0 to 100
 >>> a*5
RangedNumber(50, 0, 100)
 >>> 10*a
RangedNumber(100, 0, 100)
 >>> 11*a
Traceback (most recent call last):
   File "<stdin>", line 1, in ?
   File "spam.py", line 67, in __rmul__
     return RangedNumber(x, low, high)
   File "spam.py", line 8, in __init__
     raise ValueError("value %r not in range %r to %r" %
ValueError: value 110 not in range 0 to 100
 >>> 0-a
Traceback (most recent call last):
   File "<stdin>", line 1, in ?
   File "spam.py", line 54, in __rsub__
     return RangedNumber(x, low, high)
   File "spam.py", line 8, in __init__
     raise ValueError("value %r not in range %r to %r" %
ValueError: value -10 not in range 0 to 100
 >>> a-0
RangedNumber(10, 0, 100)
 >>> b = RangedNumber(18, 5, 20)
 >>> b = RangedNumber(18, 5, 30)
 >>> a+b
RangedNumber(28, 5, 30)
 >>>

				Andrew
				dalke at dalkescientific.com



More information about the Python-list mailing list