Python range 的长度上限:远处的元素能取到,为什么 len 却抛出溢出异常

前天 3阅读

程序用 range 表示很大的连续编号空间,创建成功,索引也能取值;加入一行 len 作进度统计,却触发 OverflowError。这并不意味着编号超出了 Python 整数能力,而是序列项数超过了 CPython 长度接口可表示的上限。

下面使用当前解释器的 sys.maxsize 构造边界,只取少数元素,不把巨大范围展开成列表。保存为 demo.py,用 CPython 3.12 运行 python demo.py;该长度上限是本例明确依赖的实现细节。

Python range 的长度上限:远处的元素能取到,为什么 len 却抛出溢出异常

AI模型生成概念示意:稀疏编号线可以定位远处元素,小型长度计数器却容不下总项数;不是内存或性能测试截图。

import sys

stop = sys.maxsize + 2
wide = range(stop)
assert wide[0] == 0
assert wide[sys.maxsize + 1] == sys.maxsize + 1
assert wide[-1] == stop - 1
print("first:", wide[0])
print("large index works:", wide[sys.maxsize + 1] == stop - 1)

try:
    len(wide)
except OverflowError:
    print("wide length: overflow")
else:
    raise AssertionError("expected CPython length limit")

head = list(wide[:3])
print("small slice:", head)
assert head == [0, 1, 2]

start = 10 ** 30
tiny = range(start, start + 3)
print("large values, small length:", len(tiny))
assert len(tiny) == 3
assert tiny[-1] == start + 2

count_for_this_range = wide.stop - wide.start
print("explicit count exceeds maxsize:", count_for_this_range > sys.maxsize)
assert count_for_this_range == stop

值很大与项数很多要分别检查

前两行 first: 0 和 large index works: True 证明范围对象正常工作,甚至能定位到超过 sys.maxsize 的索引。range 根据起点、步长和索引计算元素,不需要在此之前生成全部编号;负索引也可以从范围末尾定位。

wide length: overflow 才是异常发生的地方。sys.maxsize 对应平台长度类型能够容纳的最大值,常见64位环境是二的六十三次方减一。它不是 Python int 的最大数。不要把一次 len 失败转换成“输入整数非法”,这样会混淆数据范围与具体接口限制。

只展开确实需要检查的小窗口

small slice: [0, 1, 2] 来自先切片、后转列表。切片仍是 range,只有三个元素被物化。若反过来先 list(wide),就会试图创建难以容纳的完整列表;这种操作既没有必要,也不是验证巨大范围是否有效的合适办法。

large values, small length: 3 提供反例:起点已经是十的三十次方,项数却只有三,所以 len 可以返回三。真正触及限制的是结果项数,不能只看到 start 或 stop 很大就推断长度一定溢出。

最后一行 explicit count exceeds maxsize: True 说明普通整数运算仍可保存本例总数。这里范围从零开始、步长为一,项数才恰好等于 stop 减 start。不要把这条简化公式复制给负步长、非一步长或空范围;那些情况需要单独处理开闭边界与方向。

如果进度条或第三方接口必须接收有限长度,可把工作分成可控批次,每批只传自己的局部长度,同时单独保存大整数总量。无需为了显示百分比而预先遍历所有元素。表示范围的内存很小,也不表示遍历范围所需时间很少,这两个成本必须分别估计。

资料核对日期:2026年10月2日。代码在本地 Python 3.12.14 实际运行并通过断言;结果对应文中固定输入。

参考资料

文章版权声明:除非注明,否则均为云鹊BLOG原创文章,转载或复制请以超链接形式并注明出处。