2.12. 循环

循环会反复运行同一段代码。Python 有两种形式:while,只要某个条件保持为真就一直继续;以及 for,它会遍历一个序列中的各个元素。

并排的流程图。while:测试条件,若为真则运行 循环体,重复。for:从可迭代对象中取下一个元素, 运行循环体,重复直到耗尽。

while 不断测试一个条件;for 则遍历一个序列直到它被耗尽。

2.12.1. while 循环

while 循环在每次迭代之前测试它的条件,并运行循环体直到测试变为假:

count = 0
while count < 5:
    print(count)
    count += 1

输出:

0
1
2
3
4

如果条件在开始时为真且永远不会变为假,循环就会永远运行下去。while True: 是主循环的标准写法,通过 break 显式退出:

while True:
    step()
    if done():
        break

2.12.2. for 循环

for 循环遍历一个可迭代对象的各个元素 —— 可以是列表、元组、字符串、字节串、字典,或任何其他支持迭代的对象:

for fruit in ["apple", "banana", "cherry"]:
    print(fruit)

输出:

apple
banana
cherry

同样的形态也适用于字符串,此时每个元素都是一个单字符的字符串:

for letter in "OpenMV":
    print(letter)

输出:

O
p
e
n
M
V

直接迭代字典会按插入顺序产出它的键:

for key in {"a": 1, "b": 2}:
    print(key)

输出:

a
b

每一轮都会把循环变量(fruitletterkey)绑定到下一个元素。循环结束后,该变量仍保留最后一次迭代时的值。

2.12.3. range

对于遍历一段数值区间的 for 循环,使用 range()

  • range(stop) —— 0, 1, ..., stop - 1。

  • range(start, stop) —— start, start + 1, ..., stop - 1。

  • range(start, stop, step) —— 带自定义步长(负值表示倒数)。

for i in range(5):           # 0, 1, 2, 3, 4
    print(i)

for i in range(2, 8, 2):     # 2, 4, 6
    print(i)

for i in range(10, 0, -1):   # 10, 9, ..., 1
    print(i)

range() 惰性地产生值 —— 它不会在内存中构建一个列表。要得到一个真正的 list,可以把它包起来:list(range(10))

2.12.4. enumerate

当循环同时需要索引和元素时,enumerate() 会产出 (index, item) 对:

for i, name in enumerate(["a", "b", "c"]):
    print(i, name)
# 0 a
# 1 b
# 2 c

通过传入第二个参数可以让索引从零以外的值开始:enumerate(items, start=1)

2.12.5. zip

要同步遍历两个(或更多)可迭代对象,使用 zip()。它在每个位置产出一个元组,并在最短的输入耗尽时停止:

names  = ["alice", "bob", "carol"]
scores = [88, 92, 70]

for name, score in zip(names, scores):
    print(name, score)

输出:

alice 88
bob 92
carol 70

2.12.6. 使用 := 进行内联赋值

海象运算符 := 是一种既是赋值又是表达式的写法。它在绑定一个名称的同时求值为相同的值。在 while 循环中,这把常见的“读取、检查、循环体”模式压缩成了一行:

# without walrus
value = next_value()
while value is not None:
    process(value)
    value = next_value()

# with walrus
while (value := next_value()) is not None:
    process(value)

这两种形式做的是同一件事。当赋值的重复确实损害了可读性时,就采用 :=;不要只为了显得聪明而使用它。在大多数位置都需要加括号,以保持表达式无歧义。