为什么 six.py 使用自定义 class 来查找 MAXSIZE?

Why does six.py use custom class for finding MAXSIZE?

我正在查看 six.py in the django utils 的代码,对于非 Jython 实现,它试图找到 int 的 MAXSIZE。现在,这样做的方式很有趣——不是在语句本身捕获异常,而是将语句包装在自定义 class 中的 __len__ 方法中。这样做的原因可能是什么?

class X(object):
    def __len__(self):
        return 1 << 31
try:
    len(X())
except OverflowError:
    # 32-bit
    MAXSIZE = int((1 << 31) - 1)
else:
    # 64-bit
    MAXSIZE = int((1 << 63) - 1)
del X

如果我没记错的话,同样可以缩短为下面的内容,对吧?

try:
    1 << 31
except OverflowError:
    # 32-bit
    MAXSIZE = int((1 << 31) - 1)
else:
    # 64-bit
    MAXSIZE = int((1 << 63) - 1)
python3 中的

int 是 class 的多语言类型,可以表示机器整数和大整数;取代 python2 中 intlong 之间区别的功能。在 python3 上,构造 int(1 << n) 永远不会引发错误。

因此,为了解决这个问题,六使用了一个巧妙的技巧,即 强制 python 将某些内容塞入机器大小的 int 中。 len 内置函数总是尝试将 __len__ 的 return 值转换为机器大小的东西:

>>> class Lengthy(object):
...     def __init__(self, x):
...         self.x = x
...     def __len__(self):
...         return self.x
...     
>>> int(1<<100)
1267650600228229401496703205376L
>>> type(int(1<<100))
<type 'long'>
>>> len(Lengthy(1<<100))
Traceback (most recent call last):
  File "<ipython-input-6-6b1b77348950>", line 1, in <module>
    len(Lengthy(1<<100))
OverflowError: long int too large to convert to int

>>> 

或者,在Python3中,异常略有不同:

>>> len(Lengthy(1<<100))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OverflowError: cannot fit 'int' into an index-sized integer
>>>