这是一个非常经典的问题,因为它触及了 Python 2 和 Python 3 之间一个重要的区别。

- Python 2: 同时拥有
range()和xrange()。range(): 返回一个完整的 列表,所有数字都存储在内存中。xrange(): 返回一个 xrange 对象,这是一个“序列类型”,它只在需要时才生成数字,非常节省内存。
- Python 3: 只有
range()。- Python 3 的
range()行为完全等同于 Python 2 的xrange(),它返回的是一个range对象,而不是列表,同样是惰性计算的,非常节省内存。 - 如果你需要在 Python 3 中获取一个列表,可以使用
list(range())来转换。
- Python 3 的
xrange 是 Python 2 的一个内存优化版本,而 Python 3 直接将这个优化版本作为了标准的 range 函数。
详细对比
Python 2 中的 range() vs xrange()
在 Python 2 中,这是一个重要的选择,尤其是在处理大范围数字时。
range()
- 类型: 返回一个
list(列表)。 - 工作方式: 立即生成,当你调用
range(1000000)时,Python 会立刻在内存中创建一个包含 1, 0, 1, 2, ..., 999,999 这 100 万个数字的列表。 - 内存消耗: 高,列表的大小与
range的大小成正比,对于非常大的数字(如range(100000000)),会消耗大量内存,甚至可能导致程序崩溃。 - 速度: 访问速度很快,因为数据已经全部加载到内存中。
示例 (Python 2):
# 创建一个包含 0 到 9 的列表 r = range(10) print type(r) # <type 'list'> print r # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] print r[5] # 5
xrange()
- 类型: 返回一个
xrange对象,它不是一个列表,而是一个实现了序列协议的对象。 - 工作方式: 惰性计算。
xrange对象不会一次性生成所有数字,它只记住start,stop, 和step的值,当你需要访问某个数字(例如通过索引x[5])或迭代它时,它才会根据规则计算出那个特定的数字。 - 内存消耗: 非常低,无论
range有多大,xrange对象本身只占用固定的少量内存,因为它只存储了几个参数。 - 速度: 迭代时速度和
range差不多,但创建对象的速度非常快,因为它不需要分配大量内存。
示例 (Python 2):

# 创建一个 xrange 对象 xr = xrange(10) print type(xr) # <type 'xrange'> print xr # xrange(10) # print xr[5] # 这也是可以的,xrange支持索引,它会实时计算 print list(xr) # 如果强制转换为列表,才会生成所有数字: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Python 2 中的选择建议:
- 如果只是想在一个
for循环中迭代,或者只需要访问序列中的个别元素,始终使用xrange(),这是更高效、更安全的选择。 - 如果你确实需要一个包含所有数字的列表(用于多次索引访问、切片或传递给一个只接受列表的函数),那么才使用
range()。
Python 3 中的 range()
Python 3 的设计者认为 xrange() 的行为更符合大多数实际场景的需求,于是做出了统一。
- 类型: 返回一个
range对象,这个对象的行为和 Python 2 的xrange几乎完全一样。 - 工作方式: 惰性计算,和
xrange一样,它只在需要时才生成数字。 - 内存消耗: 非常低,这是
range在 Python 3 中的主要优点。 - 特点:
range对象是不可变的,你不能修改它里面的元素。
示例 (Python 3):
# 创建一个 range 对象 r = range(10) print(type(r)) # <class 'range'> print(r) # range(0, 10) # print(r[5]) # 可以索引访问,输出 5 # for i in r: # 可以迭代 # print(i) # 如果你需要一个列表 r_list = list(r) print(r_list) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] print(type(r_list)) # <class 'list'>
Python 3 中的优势:
因为 range 是惰性的,所以你可以用它来表示非常大的数字范围,而不会耗尽内存。

# 在 Python 3 中,这是完全可行的,只消耗极少量内存 # 一个包含 0 到 999,999,999 的数字序列的“表示” huge_range = range(1000000000) # 只有在真正需要时,内存才会被消耗 # 当你尝试把它转换成列表时,程序可能会因为内存不足而崩溃 # huge_list = list(huge_range) # 警告:这会耗尽你所有的内存! # 但迭代它,或者取一个元素,是没问题的 print(huge_range[500000000]) # 500000000
总结表格
| 特性 | Python 2 range() |
Python 2 xrange() |
Python 3 range() |
|---|---|---|---|
| 返回类型 | list |
xrange 对象 |
range 对象 |
| 内存使用 | 高,立即分配所有数字的内存 | 低,只存储参数,惰性计算 | 低,只存储参数,惰性计算 |
| Python 3 中的等价物 | (无) | Python 3 range() |
(自身) |
| 主要用途 | 需要一个真实的列表时 | 迭代、for 循环、索引访问 | 迭代、for 循环、索引访问 |
| 性能 | 创建时慢,访问快 | 创建快,迭代/访问高效 | 创建快,迭代/访问高效 |
现代编程建议
-
如果你使用的是 Python 3:
- 忘掉
xrange,它不存在了。 - 在所有需要生成数字序列进行循环或索引的地方,放心大胆地使用
range()。 - 只有当你明确需要一个列表时,才使用
list(range(...))。
- 忘掉
-
如果你在维护 Python 2 代码,或需要编写兼容 Python 2 和 3 的代码:
-
为了内存效率和代码的健壮性,优先使用
xrange()。 -
一个常见的兼容性写法是:
try: # Python 2 range = xrange except NameError: # Python 3 pass # 现在在代码中直接使用 range() 即可 # 在 Python 2 中它会指向 xrange,在 Python 3 中它就是 range for i in range(1000000): pass这种写法让代码在两个版本中都能高效地运行。
-
