range 与 xrange
range() 和 xrange() 是 Python 2 中生成整数序列的两个函数。它们看起来相似,但内存行为截然不同——这是 Python 2 中最需要理解的区别之一,也是 Python 3 直接移除 xrange、让 range() 继承其行为的原因。
range():返回列表
range(stop) 或 range(start, stop[, step]) 返回一个包含整数的列表:
print range(5) # [0, 1, 2, 3, 4]
print range(2, 6) # [2, 3, 4, 5]
print range(0, 10, 2) # [0, 2, 4, 6, 8]
print range(10, 0, -2) # [10, 8, 6, 4, 2]
参数规则:
- 只有一个参数时,是
stop,start默认为 0,step默认为 1 - 有两个参数时,是
start和stop - 有三个参数时,第三个是
step,可以为负数(倒序) - 范围是左闭右开:包含
start,不包含stop
print range(3) # [0, 1, 2],不包含 3
print range(1, 4) # [1, 2, 3],不包含 4
因为 range() 返回列表,它会一次性在内存中创建所有整数。对于大范围,这会消耗大量内存:
# 创建一个包含 1000 万个整数的列表
big_list = range(10000000)
print len(big_list) # 10000000
# 内存占用约 80MB(每个整数约 28 字节)
xrange():返回惰性迭代器
xrange() 的语法与 range() 完全相同,但它返回的是一个xrange 对象——一种惰性计算的迭代器:
print xrange(5) # xrange(5)
print list(xrange(5)) # [0, 1, 2, 3, 4]
xrange 对象不存储所有整数,只在需要时生成下一个。它占用的内存是固定的,与范围大小无关:
# 几乎不占用额外内存
big_iter = xrange(10000000)
print big_iter # xrange(10000000)
print len(big_iter) # 10000000(支持 len)
xrange 支持索引和 len(),但不支持切片:
x = xrange(10)
print x[5] # 5,支持索引
print len(x) # 10,支持长度
print x[2:5] # TypeError: sequence index must be integer, not 'slice'
实际对比
import sys
# range 的内存占用
r = range(1000000)
print sys.getsizeof(r) # 约 8000048 字节(8MB)
# xrange 的内存占用
x = xrange(1000000)
print sys.getsizeof(x) # 约 40 字节
在循环中使用,两者效果相同:
# 效果相同,但 range 先分配 1000 万个整数的内存
for i in range(10000000):
if i == 5:
break # 只用到前 5 个,但 1000 万个整数都已创建
# xrange 只生成用到的整数
for i in xrange(10000000):
if i == 5:
break # 只生成 0,1,2,3,4,5,内存占用极小
选择建议
| 场景 | 推荐 |
|---|---|
| 小范围(< 1000) | range() 或 xrange() 均可 |
| 大范围循环 | xrange() |
| 需要列表操作(切片、修改) | range() |
| 需要与旧代码兼容 | xrange()(Python 3 中 range() 就是 xrange() 的行为) |
# 小范围:range 更直观
for i in range(5):
print i
# 大范围:必须用 xrange
for i in xrange(1000000):
process(i)
# 需要列表时:显式转换
numbers = list(xrange(10)) # [0, 1, 2, ..., 9]
Python 3 的变化
Python 3 中 range() 的行为与 Python 2 的 xrange() 完全一致,返回惰性序列。xrange() 这个名字被移除了。如果你在写兼容两个版本的代码,可以这样处理:
try:
xrange
except NameError:
xrange = range # Python 3 中没有 xrange,用 range 替代
for i in xrange(100):
print i
理解 range 和 xrange 的区别,是写出内存高效 Python 2 代码的关键。记住一个原则:只要用于循环,优先用 xrange()。