range对象几乎不占内存,因为它仅存储start、stop、step三个整数(约48–96字节),访问时才通过公式start + i * step按需计算值,不预存任何实际数字。

range 对象为什么几乎不占内存
因为 range 不是容器,而是一个只存三个整数(start、stop、step)的不可变序列对象。它内部不存储任何实际数字,访问某个位置(比如 r[999999])时才用公式 start + i * step 算出结果。一个 range(10**18) 和 range(5) 在内存里都只占约 48–96 字节。
range 和 list(range()) 的内存差异在哪
关键区别在“是否实例化所有元素”:
-
range(10**6):仅存参数,≈ 48 字节 -
list(range(10**6)):创建并存储 100 万个int对象,每个至少 28 字节(CPython),加上列表头开销,总内存超 28 MB - 更极端情况:
list(range(10**9))很可能直接触发MemoryError,而range(10**9)毫无压力
哪些操作会悄悄让 range “破功”爆内存
看似 harmless 的转换或使用方式,实则立刻放弃惰性优势:
快速生成专业的 Python 脚本和应用代码。一键创建完整项目结构,支持CLI、API、爬虫、Bot、Django等多种项目类型,包含完整的项目结构、配置文件、依赖管理、测试、README和文档。
- 显式调用
list(range(n)):强制展开全部元素 - 用
json.dumps(list(range(n)))或pickle.dump(list(range(n)), ...):必须先转成列表 - 误以为
range支持.append()或.extend(),结果写range(5).append(5)报AttributeError,但有人会先list(range(5))再操作——这步就已吃掉内存 - 在调试时直接
print(range(10**6)):虽然不会崩,但某些 IDE 或 REPL 会尝试预览前若干项,间接触发部分迭代;真正危险的是后续无意识的list(...)
in、len、切片这些操作为什么还是 O(1)
它们全靠数学推导,完全绕过遍历:
-
len(r)→ 直接算(r.stop - r.start + r.step - 1) // r.step(带符号修正) -
5 in r→ 判断5 >= r.start且(5 - r.start) % r.step == 0且5 (正步长下) -
r[1234567]→ 单次加法:r.start + 1234567 * r.step -
r[2:10:3]→ 返回新range对象,参数重算,不碰原范围里的任何一个值
真正容易被忽略的点是:range 的轻量,只在它始终是 range 类型时成立;一旦你把它喂给任何需要“真实数据”的上下文(比如 NumPy 构造、SQL 参数绑定、JSON 序列化),它就立刻失去这个优势。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










