Python 3 的 range 是懒加载的不可变序列,仅存 start、stop、step 三个整数,内存占用 O(1),支持索引、切片和高效遍历,非列表也非迭代器。

Python 3 的 range 不返回列表,是因为它根本就不是列表——它是一个不可变的、支持索引和切片的懒序列对象,只在需要时才计算具体数值,内存占用恒定为 O(1)。
range 对象不是列表,也不能用 list() 强转就当没事发生
很多人看到 range(1000000) 还以为“这不就是个大列表”,结果一用 list(range(1000000)) 就爆内存。其实 range 对象本身只存三个整数:start、stop、step,连一个中间数字都没生成过。
常见错误现象:
- 误以为
range(10**8)占用大量内存(实际约 48 字节) - 对
range对象反复调用list(),导致重复构造百万级列表 - 在循环中写
for i in list(range(n)):,完全抵消了懒加载优势
正确做法:
- 直接用
for i in range(n):—— 它内部按需计算,不额外分配内存 - 需要随机访问时,用
range_obj[999]索引,仍是 O(1) 时间 - 真要转列表?只在明确需要「可变」「多次遍历」「支持
.append()」时才做,且确认n足够小
为什么 for 循环能直接遍历 range,但它又不是迭代器
range 是可迭代对象(有 __iter__),但不是迭代器(没有 __next__)。每次 for 循环都会调用 iter(range_obj) 拿到一个新迭代器,所以可以无限重用。
对比真实迭代器(比如 iter([1,2,3]) 或生成器):
- 迭代器只能用一次:第二次
for循环啥也不输出 -
range可以反复遍历:list(range(3)) == [0,1,2],再跑一遍还是[0,1,2] - 这意味着你不需要担心“range 被消耗光了”,也别试图对它调用
next()
容易踩的坑:
-
next(range(5))→TypeError: 'range' object is not an iterator - 误把
range当成生成器,在协程或异步代码里传给期望迭代器的函数(如itertools.chain需要迭代器,得先包一层iter())
range 切片和布尔判断的隐含行为
range 支持切片(如 range(10)[2:7:2]),返回的仍是 range 对象,不是列表。这点常被忽略,但直接影响性能和内存。
关键细节:
-
range(100)[10:90]不会生成 80 个数,只新建一个等价的range(10, 90) -
bool(range(0))是False,bool(range(1))是True—— 它根据start >= stop(正步长时)判断是否为空,不是看“有没有元素被算出来” -
len(range(10**12))瞬间返回,因为长度是公式计算:(stop - start + step - 1) // step,不遍历
性能影响:
- 用
range做大范围索引(如my_list[range(100000)])比用list(range(...))快且省内存 - 但注意:
range切片不支持负索引以外的负步长嵌套逻辑,某些边界情况会静默返回空range
真正要注意的,不是 range “多聪明”,而是它只在你显式触发计算时才干活——比如索引、len()、list()、for 循环。一旦你写了 list(range(10**6)),懒加载就彻底失效了;而如果只是传给 enumerate 或 zip,它依然保持轻量。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











