In Python 3 I have a class representing a range [x,y] of values and computing the length of such range.
If the length is too large, I'm not sure how to catch the OverflowError exception inside the class itself. It is raised only in the outer code using a class instance...
class ValRange:
val_min = None
val_max = None
range_len = 0
def __init__(self, val_min, val_max):
self.val_min = val_min
self.val_max = val_max
def __len__(self):
if (self.val_min is not None and
self.val_max is not None):
length = 0
try:
length = int(self.val_max) - int(self.val_min) + 1
except OverflowError as e:
# Somehow no exception is caught here...
print('OverflowError...')
length = 10**5 # arbitrarily large number
except Exception as e:
print(e)
if length > 0:
self.range_len = length
return self.range_len
import traceback
import uuid
x = uuid.UUID('00000000-cb9d-4a99-994d-53a499f260b3')
y = uuid.UUID('ea205f99-0564-4aa0-84c3-1b99fcd679fd')
r = ValRange(x, y)
try:
print(len(r))
except:
# The exception is caught in this outer code and not in the class itself. Why?
print(traceback.format_exc())
# The following, which is equivalent to the operations in the
# code above, will work.
a = int(y) - int(x) + 1
print(a)
This is what happens upon execution:
Traceback (most recent call last):
File "/home/rira/bugs/overflow.py", line 35, in <module>
print(len(r))
OverflowError: cannot fit 'int' into an index-sized integer
311207443402617699746040548788952897867
That's because the
OverflowErrordoesn't occur within your magic__len__()method - Python is perfectly capable of handling much bigger integers than that - but in CPythonlen()itself is implemented asPyObject_Size()which returns aPy_ssize_t, which is limited to2^31-1(32-bit) or2^63-1(64-bit) and thus the overflow occurs when your__len__()result is coerced to it.You can do a pre-check before returning the result to make sure you capture the overflow before it even occurs, something like: