Python range(start,stop,step)参数含义与默认规则
深入解析 Python 内置函数 range(start, stop, step) 的三个参数含义、缺省默认规则、左闭右开区间机制以及正负步长序列生成原理。
在 Python 中,range() 是最常用于生成一系列有序整数的不可变序列类型。它最多可接受三个整数参数:start(起始值)、stop(终止值)和 step(步长)。理解这三个参数的内在顺序、缺省默认值以及“左闭右开”截断规则,是掌握循环遍历、索引控制与切片逻辑的基础。
一、三个参数的具体定义与默认规则
range() 拥有两种基础调用原型。根据传入参数的数量(1个、2个或3个),Python 解析参数的具体位置和默认赋值具有确定性逻辑:
start(起始值):序列生成的第一个整数。属于闭区间包含端。如果调用时仅传入 1 个参数,start将自动采用默认值0。stop(终止值):序列生成的边界终点。属于开区间排除端,生成的数值序列绝对不会包含该值本身。stop是range()中唯一没有默认值的参数,任何调用都必须直接或间接指定。step(步长):序列中每相邻两个整数之间的增量或跨度。如果调用时仅传入 1 个或 2 个参数,step自动采用默认值1。步长必须是非零整数,传入0会立即抛出ValueError。
| 调用形式 | 显式传入参数 | 隐式默认值 | 最终等效完整形式 |
|---|---|---|---|
range(stop) |
仅指定终止值 stop |
start = 0, step = 1 |
range(0, stop, 1) |
range(start, stop) |
指定起始与终止值 | step = 1 |
range(start, stop, 1) |
range(start, stop, step) |
完整指定三参数 | 无缺省值 | range(start, stop, step) |
二、理解“左闭右开”截断规则
初学者在使用 range() 时最常见的误区是:期望 range(1, 5) 生成数字 5,或者误以为 range(10) 会产生 10 个数字并以 10 结尾。
Python 采用的是数学上的左闭右开区间(Half-open Interval),用数学符号表示为 [start, stop)。这意味着:
- 左边界
start处于闭区间,即序列的第一个元素必然是 start(假设序列非空)。 - 右边界
stop处于开区间,即序列中的任意元素绝对不能等于或越过 stop。
这种设计并非疏漏,而是遵循了计算机科学经典设计原则(如 Edsger W. Dijkstra 在《为什么编号应该从零开始》中所述):
- 元素数量直接等于差值:在默认步长
step=1时,生成的元素个数恰好为stop - start。例如range(0, 10)长度刚好是10 - 0 = 10,无需在公式中额外进行“+1”或“-1”的心智修正。 - 连续分段首尾无缝对接:如果需要把一个大区间无缝切分为两段,第一个区间的终止点可以直接作为第二个区间的起始点,如
range(0, 5)与range(5, 10),二者既不会重叠,也不会漏掉边界元素 5。 - 与 0 基索引完美对齐:Python 中列表、元组、字符串的索引均从 0 开始。对于长度为
len(arr)的列表,range(len(arr))产生的索引序列恰好是0, 1, ..., len(arr) - 1,完全覆盖合法下标且绝不越界。
三、数值序列生成的推导步骤与运行流程
为了在脑海中清晰建立 range() 的工作模型,我们可以把 range(start, stop, step) 在循环时的求值过程拆解为标准的状态机推导步骤:
- 第一步(初始化):将内部计数器
current置为start。检查step是否为 0,若为 0 则直接抛出ValueError异常终止。 - 第二步(边界条件判断):根据步长方向判断
current是否仍处于有效范围内:- 当
step > 0时,检查条件为current < stop。 - 当
step < 0时,检查条件为current > stop。
- 当
- 第三步(产出数据):若判断条件成立,将
current作为当前元素产出(yield);若条件不成立,立即退出迭代,stop及后续数值均不产生。 - 第四步(累加更新):计算
current = current + step,随后返回第二步重新进行边界判断。
四、正向步长与反向步长(递增与递减)对比
step 参数不仅决定相邻两个数的跳跃跨度,还严格决定了序列生成的方向。
1. 正向递增(step > 0)
当 step 为正整数时,序列从 start 开始向右递增。此时若要产出元素,必须保证 start < stop。终止条件是:当下一个预期数值大于或等于 stop 时立即停止。
# 正向步长示例:从 2 开始,到 9 结束(不含 9),步长为 2
seq_positive = list(range(2, 9, 2))
# 输出结果:[2, 4, 6, 8]
2. 反向递减(step < 0)
当 step 为负整数时,序列从 start 开始向左递减。此时若要产出元素,必须保证 start > stop。终止条件随之变为:当下一个预期数值小于或等于 stop 时立即停止。
# 反向步长示例:从 9 开始,到 2 结束(不含 2),步长为 -2
seq_negative = list(range(9, 2, -2))
# 输出结果:[9, 7, 5, 3]
start < stop 却设置了负步长(例如 range(2, 8, -1)),或者 start > stop 却设置了正步长(例如 range(8, 2, 1)),Python 并不会报错,而是直接判定初始值已超出终止边界,最终产生一个空序列。
五、range 对象的底层特性与常见注意事项
在实际编程过程中,围绕 range() 还有以下几条关键规则与特性需要牢记:
1. 惰性求值与常数级内存开销($O(1)$)
在 Python 3 中,range 并不是一个预先生成所有元素的 list,而是一个特殊的不可变序列类型。无论范围多大,它只在内部存储 start、stop、step 三个数值,并在被请求时按需计算:
import sys
r_small = range(10)
r_huge = range(10_000_000_000)
# 两者在内存中所占用的字节大小完全一致
print(sys.getsizeof(r_small)) # 输出 48 字节 (具体数值视系统平台而定)
print(sys.getsizeof(r_huge)) # 输出 48 字节
2. 支持序列操作:索引、切片、长度与快速包含检测
既然 range 是序列类型,它完全支持正负索引、分片以及 len() 计算。更为高效的是,Python 对 range 对象的 in 成员判断进行了针对性数学优化:基于数学公式可在 $O(1)$ 常数时间内判定一个数是否落在此等差数列中,而不需要像普通列表那样逐项遍历扫描。
r = range(10, 100, 5)
print(len(r)) # 18
print(r[0]) # 10 (支持正向索引)
print(r[-1]) # 95 (支持反向索引)
print(25 in r) # True (数学公式秒算,时间复杂度 O(1))
print(26 in r) # False (不在等差步长上)
3. 参数必须为整型,严禁浮点数与零步长
- 类型限制:所有参数都必须是整数(
int或实现了__index__的整型对象)。如果传入浮点数(例如range(0.1, 1.0, 0.1)),解释器会抛出TypeError: 'float' object cannot be interpreted as an integer。若需要浮点数等差数列,建议使用numpy.arange()或numpy.linspace()。 - 非零步长:
step绝不能为 0,否则会抛出ValueError: range() arg 3 must not be zero。
六、总结
掌握 Python range(start, stop, step) 可以归纳为三句实用口诀:
- 一参为止,从零起步:当只写一个数字时,它是终止值
stop,起始值默认为0,步长默认为1。 - 左闭右开,止值不及:包含起始点
start,但在触及或跨越stop时立即切断,stop本身永不入列。 - 步长定势,同向方行:步长正负决定序列递增或递减方向。起点到终点的方向必须与步长符号严格一致,否则将得到空序列。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









