HOWTO · Python

在 Python 中向后迭代

这篇文章讨论了可用于在 Python 中向后迭代的函数和方法。

本页内容

反向迭代是指从序列的最后一项开始,依次访问到第一项。Python 提供了几种实现方式,适合哪一种取决于你只需要值、需要修改序列,还是需要每一项的原始索引。下面的示例使用列表;不过,reversed() 和切片也适用于字符串和元组。

使用 reversed() 反向迭代

如果你想从序列末尾向开头读取内容,同时保持序列不变,可以使用 reversed()。它会返回一个迭代器,因此不会另外创建一份值的列表。源列表仍保持原有顺序。

运行以下示例:

本节中的代码以及显示的标签或输出仍为英文。

items = ["first", "second", "third"]
for item in reversed(items):
    print(item)
third
second
first

当你只需要按反向顺序处理序列中的值时,这通常是一个不错的默认选择。循环推进时,迭代器会逐步消耗;如果需要再次遍历,请重新调用 reversed(items)。序列必须支持反向迭代。

在 Python 中使用 range() 反向迭代

当循环需要使用数字位置(例如按索引更新元素)时,可以使用 range()。它的参数是 range(start, stop, step)。负步长会让数值递减,而且 stop 值不包含在结果中。例如,range(10, 0, -1) 会生成从 10 到 1 的值;range(10, -1, -1) 则会生成从 10 到 0 的值。

本节中的代码以及显示的标签或输出仍为英文。

items = ["first", "second", "third"]
for index in range(len(items) - 1, -1, -1):
    print(index, items[index])

第一个索引是 len(items) - 1,也就是最后一个有效位置。stop 设为 -1,这样循环会先包含索引 0,然后才停止。一个常见错误是使用 range(len(items) - 1, 0, -1);由于 range() 不会包含 stop 值,这样会跳过索引 0。

使用切片反转序列

步长为 -1 的切片写作 items[::-1],它会创建一个新列表,其中的元素顺序与原列表相反。之后,你可以遍历这个列表,也可以将它保留以供后续使用。

本节中的代码以及显示的标签或输出仍为英文。

items = ["first", "second", "third"]
backward = items[::-1]
print(backward)

与 reversed() 不同,切片会分配内存来创建反向副本。如果你需要保留反向排列的值,这会很有用,但额外内存用量与序列长度成正比。只需访问元素时选择 reversed();需要一个独立的反向序列时选择切片。

使用 while 循环

while 循环可以让你直接控制索引,以及每次迭代之间要执行的操作。从最后一个有效索引开始,处理该项,然后递减索引。请确保循环条件包含索引 0,并且每次循环都会更新索引;否则循环可能过早停止,或无法继续推进。

本节中的代码以及显示的标签或输出仍为英文。

items = ["first", "second", "third"]
index = len(items) - 1
while index >= 0:
    print(items[index])
    index -= 1

当循环的停止规则或索引更新属于更大算法的一部分时,这种模式很有用。对于简单的反向遍历,reversed() 通常写法更简洁,也更清楚地表达了意图。列表为空时,while 写法也能正确处理:初始索引为 -1,因此循环体不会执行。

使用 enumerate() 保留原始索引

enumerate() 通常会在遍历可迭代对象时从零开始计数。若要将反向排列的值与它们在原列表中的位置配对,可以对 reversed(items) 使用 enumerate,并将反向偏移量换算为原始索引。

本节中的代码以及显示的标签或输出仍为英文。

items = ["first", "second", "third"]
for reverse_offset, item in enumerate(reversed(items)):
    original_index = len(items) - 1 - reverse_offset
    print(original_index, item)

第一个反向偏移量是 0,对应原列表中的最后一个索引。之后每增加一个偏移量,就对应向前一个位置。这种方式无需创建反向列表,适合同时需要值及其原始位置的情况。如果只需要索引来查找或赋值,使用 range() 的方式会更直接。

如何选择方法

要清晰且节省内存地反向遍历各个值,可使用 reversed(sequence)。当循环需要处理索引时,使用 range(len(sequence) - 1, -1, -1)。需要一个独立的反向副本且额外内存可以接受时,使用 sequence[::-1]。如果算法的核心是自定义索引控制,则使用 while 循环。如果需要按反向顺序取得值并保留其原始位置,则将 enumerate(reversed(sequence)) 与索引换算结合使用。

字符串也是序列,因此同样可以使用这些方法:reversed(text) 会反向遍历字符,而 text[::-1] 会创建一个反向字符串。这些方法处理的是序列顺序;不要假设它们能为所有容器提供通用的反向遍历方式。请选择能够表达循环需求的方法,并考虑它是否会创建副本,或是否能提供原始索引。