捕获溢出错误

时间:2018-05-16 09:24:28

标签: python python-3.x overflowexception

在Python 3中,我有一个表示值[x,y]范围的类,并计算这个范围的长度。

如果长度太大,我不确定如何捕获类本身的OverflowError异常 。它只在外部代码中使用类实例...

引发
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)

这是执行时发生的事情:

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

1 个答案:

答案 0 :(得分:2)

那是因为你的魔法OverflowError方法中没有出现__len__() - Python完全能够处理比这更大的整数 - 但是在CPython中len()本身被实现为{ {3}}返回PyObject_Size(),其限制为2^31-1(32位)或2^63-1(64位),因此当您__len__()时发生溢出结果强制到它。

您可以在返回结果之前进行预检查,以确保在发生溢出之前捕获溢出,例如:

def __len__(self):
    if (self.val_min is not None and self.val_max is not None):
        length = int(self.val_max) - int(self.val_min) + 1
        if length > sys.maxsize:
            print('OverflowError...')
            length = 10**5  # arbitrarily large number
        self.range_len = length
    return self.range_len