Python range() 函数基础入门教程 – wiki基地


Python range() 函数终极入门指南:从零开始掌握数字序列的生成

欢迎来到 Python 的世界!作为一门以简洁、易读著称的编程语言,Python 提供了许多强大的内置工具,帮助我们高效地完成各种任务。在众多基础且重要的功能中,range() 函数无疑是每个初学者都必须掌握的核心内容之一。无论你是需要重复执行一段代码特定次数,还是需要生成一个数字序列用于索引或其他计算,range() 都会是你得力的助手。

本篇教程将带你深入浅出地探索 range() 函数的方方面面,从最基础的概念、不同的使用方式,到其背后的工作原理和实际应用场景,力求让你彻底理解并能熟练运用它。即使你没有任何编程基础,跟随本教程的步伐,也能轻松入门。

一、 什么是 range() 函数?

在编程中,我们经常需要处理一系列连续的数字。例如,你可能想打印从 0 到 9 的数字,或者执行某个操作 5 次。手动写出 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 或者重复写五次代码显然不够优雅,尤其当数字范围很大或者重复次数很多时。

Python 的 range() 函数正是为了解决这类问题而设计的。它是一个内置函数,主要功能是生成一个不可变的整数序列

但这里有一个非常关键的点需要初学者注意:range() 函数并不会直接创建一个包含所有数字的列表(List)。相反,它返回的是一个特殊的 range 对象。这个 range 对象是一个可迭代对象(iterable),意味着你可以遍历它(比如在 for 循环中),但它并不会在内存中一次性存储所有的数字。它只存储了序列的起始值、结束值和步长(间隔),并在需要时动态地计算出下一个数字。

这种“惰性计算”或“按需生成”的特性使得 range() 在处理非常大的数字序列时极为内存高效。想象一下,如果需要一个从 0 到 10 亿的序列,如果 range() 直接生成一个包含 10 亿个整数的列表,那将消耗巨大的内存资源。而 range 对象本身只占用极小的固定内存。

我们可以通过 type() 函数来验证 range() 返回的是什么:

python
sequence = range(5)
print(sequence)
print(type(sequence))

输出会是:

range(0, 5)
<class 'range'>

你看,它打印的是 range(0, 5) 而不是 [0, 1, 2, 3, 4],并且类型是 <class 'range'>

那么,如果我想看到 range 对象代表的实际数字序列怎么办?最常用的方法是将它转换成列表或在 for 循环中使用。

“`python

方法一:转换为列表(List)

sequence_obj = range(5)
number_list = list(sequence_obj)
print(number_list) # 输出: [0, 1, 2, 3, 4]

方法二:在 for 循环中使用(这是最常见的用法)

print(“Using range in a for loop:”)
for number in range(5):
print(number)

输出:

Using range in a for loop:

0

1

2

3

4

“`

通过这两个例子,我们对 range() 有了初步的认识:它生成数字序列的概念,返回的是一个 range 对象,并且非常适合在 for 循环中使用。

二、 range() 函数的三种形式

range() 函数非常灵活,它支持三种不同的调用方式(也称为“签名”或“重载”),以满足不同的序列生成需求。

形式一:range(stop)

这是最简单的形式,只接受一个参数 stop

  • 参数 stop: 指定序列的结束值,但请极其注意:生成的序列不包含这个 stop 值本身。也就是说,序列会一直生成到 stop - 1 为止。
  • 隐含的起始值 start: 在这种形式下,序列的起始值默认为 0
  • 隐含的步长 step: 序列中数字之间的间隔(步长)默认为 1

示例:

“`python

生成从 0 到 4 (不包括 5) 的序列

for i in range(5):
print(f”Current number: {i}”)

如果想看到列表形式

numbers = list(range(5))
print(f”List generated by range(5): {numbers}”) # 输出: [0, 1, 2, 3, 4]

另一个例子

for count in range(3):
print(“Executing iteration”, count + 1)

numbers_zero = list(range(0)) # stop 为 0 或负数,且 start 默认为 0,将生成空序列
print(f”List generated by range(0): {numbers_zero}”) # 输出: []
“`

关键点回顾 (range(stop)):

  • 从 0 开始。
  • stop - 1 结束。
  • 步长为 1。
  • 如果 stop <= 0,则生成空序列。

形式二:range(start, stop)

这种形式接受两个参数,允许你指定序列的起始值。

  • 参数 start: 指定序列的起始值。生成的序列将包含这个 start 值。
  • 参数 stop: 指定序列的结束值。和形式一一样,生成的序列不包含这个 stop 值。
  • 隐含的步长 step: 步长默认为 1

示例:

“`python

生成从 2 到 6 (不包括 7) 的序列

for i in range(2, 7):
print(f”Number: {i}”)

列表形式

numbers = list(range(2, 7))
print(f”List generated by range(2, 7): {numbers}”) # 输出: [2, 3, 4, 5, 6]

生成从 -3 到 1 (不包括 2) 的序列

neg_numbers = list(range(-3, 2))
print(f”List generated by range(-3, 2): {neg_numbers}”) # 输出: [-3, -2, -1, 0, 1]

如果 start >= stop,且步长默认为正数 1,则生成空序列

empty_seq = list(range(5, 2))
print(f”List generated by range(5, 2): {empty_seq}”) # 输出: []
“`

关键点回顾 (range(start, stop)):

  • start 开始(包含 start)。
  • stop - 1 结束。
  • 步长为 1。
  • 如果 start >= stop,则生成空序列。

形式三:range(start, stop, step)

这是最完整的形式,允许你指定起始值、结束值以及步长。

  • 参数 start: 序列的起始值(包含)。
  • 参数 stop: 序列的结束值(不包含)。
  • 参数 step: 序列中数字之间的间隔。它可以是正数(递增序列),也可以是负数(递减序列)。step 不能为 0,否则会引发 ValueError 异常。

示例(正数步长):

“`python

生成从 1 到 9,步长为 2 的序列 (奇数)

for i in range(1, 10, 2):
print(f”Odd number: {i}”)

列表形式

odd_numbers = list(range(1, 10, 2))
print(f”List generated by range(1, 10, 2): {odd_numbers}”) # 输出: [1, 3, 5, 7, 9]

生成从 0 到 14,步长为 3 的序列

step_numbers = list(range(0, 15, 3))
print(f”List generated by range(0, 15, 3): {step_numbers}”) # 输出: [0, 3, 6, 9, 12]
“`

示例(负数步长):

step 为负数时,表示生成一个递减的序列。这时,start 值必须大于 stop 值,序列才会包含元素。

“`python

生成从 10 递减到 1 (不包括 0) 的序列

for i in range(10, 0, -1):
print(f”Counting down: {i}”)

列表形式

countdown = list(range(10, 0, -1))
print(f”List generated by range(10, 0, -1): {countdown}”) # 输出: [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]

生成从 5 递减到 -4,步长为 -2 的序列

neg_step_numbers = list(range(5, -5, -2))
print(f”List generated by range(5, -5, -2): {neg_step_numbers}”) # 输出: [5, 3, 1, -1, -3]

如果 step 为负,但 start <= stop,则生成空序列

empty_neg_step = list(range(1, 10, -1))
print(f”List generated by range(1, 10, -1): {empty_neg_step}”) # 输出: []
“`

示例(步长为 0 – 错误情况):

python
try:
invalid_range = range(1, 10, 0)
except ValueError as e:
print(f"Error occurred: {e}") # 输出: Error occurred: range() arg 3 must not be zero

关键点回顾 (range(start, stop, step)):

  • start 开始(包含 start)。
  • 结束条件依赖于 step 的符号:
    • 如果 step > 0,序列持续到最后一个小于 stop 的值。
    • 如果 step < 0,序列持续到最后一个大于 stop 的值。
  • step 决定了序列中数字的间隔和方向。
  • step 不能为 0。
  • 如果 step > 0 且 start >= stop,序列为空。
  • 如果 step < 0 且 start <= stop,序列为空。

三、 为什么推荐使用 range()?(核心优势)

我们已经提到了 range() 的一些优点,现在让我们系统地总结一下:

  1. 内存效率 (Memory Efficiency): 这是 range() 最显著的优点。range 对象只存储 start, stop, step 三个值,无论序列本身有多长(哪怕是数百万、数十亿个数字),range 对象占用的内存都是固定的、非常小的。这与直接创建一个包含所有数字的列表形成鲜明对比,后者会随着序列长度线性增加内存消耗。在处理大数据或需要大量迭代时,range() 的内存优势至关重要。

    “`python
    import sys

    一个包含 1 亿个数字的 range 对象

    large_range = range(100_000_000)
    print(f”Memory size of range object: {sys.getsizeof(large_range)} bytes”)

    尝试创建一个包含 1 亿个数字的列表 (这可能会消耗大量内存,甚至导致程序崩溃)

    注意:请谨慎运行以下代码,特别是内存较小的机器

    try:

    large_list = list(range(100_000_000))

    print(f”Memory size of list with 100M integers: {sys.getsizeof(large_list)} bytes”)

    except MemoryError:

    print(“Creating a list with 100 million integers caused a MemoryError!”)

    通常 range 对象的大小非常小,而列表的大小会非常大

    “`

  2. 性能 (Performance): 由于 range 对象是按需生成数字的(惰性求值),它在创建时几乎不耗时。只有在迭代过程中,每次需要下一个数字时,才会进行简单的计算。对于只需要遍历一次序列的场景(如 for 循环),这通常比先创建一个完整的列表再遍历要快。

  3. 简洁与可读性 (Conciseness and Readability): 使用 range() 控制 for 循环是 Python 中非常惯用和清晰的做法。for i in range(10): 明确地表达了“循环执行 10 次”的意图,比手动维护计数器变量更简洁、更不易出错。

  4. 灵活性 (Flexibility): 三种形式的 range() 提供了足够的灵活性来生成各种等差整数序列,包括正向、反向、以及带有特定步长的序列。

四、 range() 与列表 (List) 的对比

虽然我们经常使用 list(range(...)) 来查看 range 对象的内容,但理解 range 对象和列表之间的本质区别非常重要:

特性 range 对象 列表 (List)
类型 range list
内存使用 极小,固定(只存 start, stop, step) 随元素数量线性增长
存储方式 不存储所有元素,按需计算 存储所有元素在内存中
可变性 不可变 (Immutable) 可变 (Mutable) – 可以增删改元素
创建时间 极快 可能较慢(取决于元素数量)
元素类型 只能是整数 (Integers) 可以包含任何类型的元素
主要用途 控制循环次数,生成数字序列 存储和操作任意数据集合
索引和切片 支持索引 ([]) 和切片 ([:]) 支持索引 ([]) 和切片 ([:])

什么时候用 range()

  • 当你想在 for 循环中迭代固定次数时。
  • 当你需要一个整数序列,但不需要立即将所有数字存储在内存中时(特别是序列很长时)。
  • 当你需要按特定步长(正或负)生成数字序列时。
  • 当你需要基于索引访问一个序列(如列表或字符串)的元素时(虽然 enumerate() 通常是更 Pythonic 的方式,但 range(len(sequence)) 也很常见)。

什么时候用列表?

  • 当你需要存储一个包含不同类型元素(不只是整数)的集合时。
  • 当你需要频繁地添加、删除或修改集合中的元素时(因为列表是可变的)。
  • 当你需要存储一个相对较小的、需要被多次随机访问或修改的数字序列时。
  • 当函数或方法明确要求一个列表作为输入时。

五、 range() 的常见应用场景

  1. 控制 for 循环执行次数:
    这是 range() 最经典、最核心的用途。

    “`python

    执行任务 5 次

    num_tasks = 5
    for i in range(num_tasks):
    print(f”Performing task {i + 1}”)

    模拟进度条

    total_steps = 10
    print(“Processing:”)
    for step in range(total_steps):
    # 做一些工作…
    print(f”Progress: {((step + 1) / total_steps) * 100:.0f}%”)
    print(“Done!”)
    “`

  2. 生成数字序列用于计算或初始化:

    “`python

    计算 1 到 100 的平方和

    sum_of_squares = 0
    for num in range(1, 101): # 注意是 101,因为 range 不包含 stop
    sum_of_squares += num * num
    print(f”Sum of squares from 1 to 100: {sum_of_squares}”)

    使用列表推导式更简洁地创建列表

    even_numbers = [x for x in range(0, 21, 2)]
    print(f”Even numbers up to 20: {even_numbers}”)

    squares = [i**2 for i in range(10)]
    print(f”Squares of first 10 non-negative integers: {squares}”)
    “`

  3. 遍历序列的索引:
    虽然直接迭代元素通常更好,但有时确实需要索引。

    “`python
    my_list = [‘apple’, ‘banana’, ‘cherry’, ‘date’]

    使用 range(len()) 访问索引和元素

    print(“\nAccessing list elements by index using range(len()):”)
    for i in range(len(my_list)):
    print(f”Index {i}: {my_list[i]}”)

    更 Pythonic 的方式:使用 enumerate()

    print(“\nAccessing list elements and indices using enumerate():”)
    for index, value in enumerate(my_list):
    print(f”Index {index}: {value}”)

    enumerate 通常是处理索引和值的首选方法,因为它更清晰易读。

    “`

  4. 结合切片(虽然不常用):
    range 对象也支持切片,返回一个新的 range 对象。

    “`python
    r = range(0, 20, 2) # 0, 2, 4, …, 18
    print(f”Original range: {list(r)}”)

    获取前 5 个元素 (对应索引 0 到 4)

    sub_range1 = r[0:5]
    print(f”Slice r[0:5]: {list(sub_range1)}”) # 输出: [0, 2, 4, 6, 8]
    print(f”Type of slice: {type(sub_range1)}”) # 输出:

    获取从索引 2 开始到结尾的元素

    sub_range2 = r[2:]
    print(f”Slice r[2:]: {list(sub_range2)}”) # 输出: [4, 6, 8, 10, 12, 14, 16, 18]
    “`

六、 重要注意事项与常见陷阱

  1. stop 值不包含: 再次强调,range(start, stop)range(stop) 生成的序列最多只到 stop - 1。这是初学者最容易犯错的地方之一。如果你需要包含 stop 值本身,你应该使用 range(start, stop + 1)(当步长为正时)。

  2. step 不能为零: range(start, stop, 0) 会导致 ValueError

  3. 负数步长: 使用负数步长时,确保 start > stop。否则,range() 会生成一个空序列。

  4. 只支持整数: range() 的所有参数(start, stop, step)都必须是整数。你不能直接使用浮点数。如果需要浮点数序列,可以考虑:

    • 使用 numpy.arange()numpy.linspace() (需要安装 NumPy 库)。
    • 自己编写生成器函数或使用列表推导式进行计算。

    “`python

    错误示例:

    range(0.5, 5.5, 0.5) # TypeError: ‘float’ object cannot be interpreted as an integer

    使用列表推导式生成近似的浮点数序列

    float_seq = [i * 0.5 for i in range(int(0.5 / 0.5), int(5.5 / 0.5))] # 需要一些计算
    print(f”Approximate float sequence: {float_seq}”)

    或者更简单的(如果知道整数范围)

    float_seq_simple = [i / 2 for i in range(1, 11)] # 生成 0.5, 1.0, …, 5.0
    print(f”Simpler float sequence: {float_seq_simple}”)
    “`

  5. range 对象是可迭代的,但不是迭代器: 这稍微有些技术性,但意味着你可以多次遍历同一个 range 对象。而迭代器(Iterator)通常只能遍历一次。

    “`python
    my_range = range(3)

    print(“First iteration:”)
    for i in my_range:
    print(i)

    print(“\nSecond iteration (possible with range object):”)
    for i in my_range:
    print(i)

    对比迭代器 (例如,通过 iter() 创建)

    my_iterator = iter(my_range)
    print(“\nIteration using an iterator (first time):”)
    for i in my_iterator:
    print(i)

    print(“\nIteration using the same iterator (second time – produces nothing):”)

    迭代器已经耗尽,再次遍历不会产生任何结果

    for i in my_iterator:
    print(i)
    print(“(Iterator is exhausted)”)
    “`

七、 总结

Python 的 range() 函数是一个基础但极其有用的工具,主要用于生成不可变的整数序列。它返回一个内存高效的 range 对象,该对象按需计算序列中的数字,而不是一次性存储所有数字。

我们学习了 range() 的三种形式:

  1. range(stop): 从 0 开始,到 stop-1 结束,步长为 1。
  2. range(start, stop): 从 start 开始,到 stop-1 结束,步长为 1。
  3. range(start, stop, step): 从 start 开始,根据 step 递增或递减,直到(但不包括)stop

range() 的核心优势在于其内存效率简洁性,特别是在控制 for 循环和处理大规模数字序列时。虽然它与列表在概念上相关(都可以表示序列),但它们在内存使用、可变性和用途上有本质区别。

掌握 range() 的用法,理解其工作原理(尤其是 stop 参数的排他性和 range 对象的惰性计算特性),是每一位 Python 学习者打好基础的关键一步。通过不断练习,在实际场景中应用 range(),你会越来越体会到它的便捷和强大。

希望这篇详细的教程能帮助你彻底理解 Python 的 range() 函数,并在你的编程之旅中灵活运用它!继续探索,享受编程的乐趣!


发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部