python 2 中 range 生成完整列表占内存,xrange 是惰性对象内存恒定;python 3 已移除 xrange,range 行为同 python 2 的 xrange,为惰性不可变序列。

Python 2 中 range 和 xrange 的内存行为差异
在 Python 2 中,range(1000000) 立即生成并存储一百万个整数的 list,占几 MB 内存;而 xrange(1000000) 只创建一个轻量级对象,内存占用恒定(约 40–50 字节),每次循环才计算下一个值。
常见错误是误以为 xrange “预生成了全部数字但没存”,其实它根本不会生成——连第一个数都只在第一次迭代时算出来。这也是为什么你不能对 xrange 对象做 .append() 或直接取 len(xrange_obj) + 1 这类操作。
-
range支持索引(range(5)[2]→2)、切片、in判断(3 in range(5)很快) -
xrange仅支持迭代、len()、reversed()和有限索引(xrange(5)[2]合法,但底层是实时计算,不是查表) - 若你在循环中可能提前
break,用xrange能省下本该分配却未使用的内存
Python 3 中已经没有 xrange
Python 3 彻底移除了 xrange,range 函数的行为完全等价于 Python 2 的 xrange:返回一个不可变的 range 对象,本质是惰性序列,不展开、不占大内存。
如果你在 Python 3 里写 xrange(10),会直接报错:NameError: name 'xrange' is not defined。这不是拼写问题,是语言层面删除。
- Python 3 的
range(10**8)占用内存 ≈ 48 字节,和range(10)几乎一样 - 它仍支持索引(
range(10)[5])、len()、count()、index(),但这些操作都是数学计算,不是遍历 - 不支持
.append()、.extend()等列表方法,也不可变
跨版本兼容写法(Python 2/3 共存项目)
如果代码必须同时跑在 Python 2 和 Python 3 上(比如遗留系统维护),不能硬写 range 或 xrange,得做适配。
最稳妥的方式是用 from builtins import range(需安装 future 或 builtins 包),或手动判断:
try:
xrange
except NameError:
xrange = range
这样后续所有循环都统一用 xrange,在 Python 2 下走原生 xrange,在 Python 3 下走重命名后的 range。
- 避免用
sys.version_info做分支判断,容易漏掉边界情况(如 PyPy、Jython) - 不要在循环外反复调用
list(range(...))—— 这会抵消所有惰性优势,且 Python 3 下list(range(N))比 Python 2 的range(N)更慢 - 如果真需要列表(比如要多次随机访问+修改),明确写
list(range(...)),别依赖隐式转换
range 对象不是生成器,但行为接近
range(Python 3)和 xrange(Python 2)都不是 Python 意义上的生成器(不基于 yield,不能用 next() 直接驱动),而是实现了 __iter__ 和 __getitem__ 的自定义类型。
这意味着:它可被 for 遍历,可被 enumerate、zip 组合,但不能被 itertools.chain 直接“展平”(除非先转成迭代器);它也比真正生成器多一些数学能力(如 range(0,10,2).count(4) 返回 1)。
- 想把它变成标准迭代器?用
iter(range(...)),但通常没必要 -
range支持负步长(range(5, 0, -1)),也支持超大整数(只要不溢出long),但起始/终止值不能是浮点数 - 最容易被忽略的一点:
range对象之间可以比较(range(5) == range(0,5)→True),但和list比较永远为False,哪怕内容相同
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











