python 3 的 range() 是不可变序列类型,支持索引、切片、len() 和 in 操作且均为 o(1),内部用数学公式计算值而不缓存整个序列;它非生成器也非迭代器,可哈希,能作字典键或集合成员。

Python 3 中没有 xrange(),不是删了,而是把它“升职”成了 range() —— 原来的 range()(生成列表)被移除了,xrange() 的行为被直接继承并成为新标准。
Python 2 中 range() 和 xrange() 的内存表现差异
在 Python 2 里,range(10**7) 会立刻分配约 80MB 内存(每个 int 在 64 位系统占 24–28 字节,加上 list 开销),而 xrange(10**7) 只占不到 1KB:它只是一个轻量对象,只存 start、stop、step 和当前迭代状态。
-
range()返回list,适合需要随机索引、切片或多次遍历的场景(比如my_list = range(100); print(my_list[50])) -
xrange()返回迭代器,只支持单次正向遍历,不能索引、不能切片(xrange(10)[5]报TypeError) - for 循环中二者性能几乎无差别,但大范围时
range()的内存压力是真实瓶颈
Python 3 中 range() 是什么类型?
Python 3 的 range() 不是生成器,也不是迭代器,而是一个不可变的序列类型(class 'range'),支持 len()、in、索引(range(10)[5])、切片(range(10)[2:6]),且所有操作都是 O(1) 时间复杂度 —— 它内部用数学公式直接计算值,不缓存整个序列。
-
type(range(10))→<class></class>(不是list,也不是generator) -
range(10**9)[999999999]瞬间返回,不触发遍历 - 但
list(range(10**9))会 OOM,和 Python 2 的range()一样危险
迁移 Python 2 代码时最常见的错误
把 xrange() 直接替换成 range() 通常能跑通,但有几处隐性陷阱:
- 依赖返回值是“可迭代但不可索引”的旧逻辑会崩:比如
if hasattr(xrange(5), '__getitem__')在 Python 2 返回False,Python 3 中range(5)返回True - 用
isinstance(x, types.GeneratorType)判断xrange()类型会失效,因为range不是生成器 - 某些 C 扩展或老库硬编码检查
type(x) is xrange,需改用isinstance(x, range)(注意 Python 2 中range是 list,所以得兼容判断) -
range()在 Python 3 中支持负步长和负索引,但行为更严格:例如range(5, 0, -1)[10]抛IndexError,而 Python 2 的xrange同样报错,这点一致
为什么不用自己实现 xrange()?
有人在 Python 3 里写 def xrange(n): return range(n),纯属冗余;更糟的是写成生成器版本(def xrange(n): for i in range(n): yield i)—— 这反而丢掉了原生 range 的所有优势:无法索引、切片变慢、len() 需遍历、in 检查退化为 O(n)。
真正容易被忽略的是:range 对象本身可哈希({range(5)} 合法),能当字典键或集合成员;而任何生成器或自定义迭代器都不能。这个特性在缓存、去重、配置映射等场景中静默生效,但很少被文档强调。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











