3. 流程控制语句

本章介绍流程控制相关的内容,例如循环语句与判断语句。

3.1. if 判断语句

判断语句是最简单的流程控制语句:

  • 语句首行由 if 开头,后接逻辑表达式,然后以冒号结尾

  • 前面提到过,语句主体代码块每行的行首需要(相比语句首行)向右缩进 4 个空格

下例判断了逻辑表达式 x > 0 的结果是 True,因此执行了代码块中的内容,使 x 增加了 1 。

[1]:
x = 1
if x > 0:
    x = x + 1
print(x)
2

if 语句也支持 else 结构,用来添加一个逻辑表达式为 False 时要执行的代码块;不过该结构不是必须的。

[2]:
x = -0.1
if x > 0:
    x = 1
else:
    x = -1
print(x)
-1

如果判断支有多个分岔,可以使用若干个 elif 在中间进行连接,开启若干个代码块:

[3]:
x = 0
if x > 0:
    print("Larger than zero")
elif x < 0:
    print("Smaller than zero")
else:
    print("Equal to zero.")
Equal to zero.

3.2. for 循环语句

for 语句的标准格式是 for xxx in yyy ,其中 yyy 需要是一个可迭代的数据(常用的是序列类的数据,比如列表),而 xxx 则是依次取 yyy 中的数值。for 语句内部的代码会在 xxx 每读取一次数据后执行一遍,直到 yyy 中的所有项被遍历。

一个简单的例子是计算 1+2+3+…+5 求和,我们这里创建一个列表 lst 来对其中的每项进行遍历:

[4]:
lst = [1, 2, 3, 4, 5]
s = 0
for i in lst:
    s += i
print(s)
15

for 语句还包含一个 else 的写法,能让循环在正常结束(即非break跳出的结束)后执行一段内容:

[5]:
s = 0
for i in (1,2,3):
    pass
else:
    s = i
print(s)
3

3.3. while 循环语句

while 语句的标准格式是 while xxx ,其中 xxx 是循环条件。如果循环条件不满足,则结束循环。

[6]:
i =  1
while i < 5:
    print(i)
    i += 1
1
2
3
4

while 语句也支持 else 写法,让循环在正常结束(即非break跳出的结束)后执行一段内容:

[7]:
s, i = 0, 1
while i <= 3:
    i += 1
else:
    s = i
print(s)
4

3.4. 循环内控制:break 与 continue

循环内控制是进行复杂循环的重要一环。

3.4.1. break:跳出

循环内在特定的条件下,需要跳出循环语句。这时需要 break 关键字,它会跳出它所在的这一层循环语句:

[8]:
for k in [1,2]:
    for j in [1,2,3]:
        if j > 2:
            break
        print("j =", j)
    print("k =", k)
j = 1
j = 2
k = 1
j = 1
j = 2
k = 2

上例中,在 j=3 时判断 j>2 为真,因此执行 break 跳出了内层的 j 循环;但外层的 k 循环并不受影响。

注意

for 或 while 循环语句如果被 break 跳出时,循环语句的 else 语句块将 不会被执行

else 语句块只在循环语句正常结束时执行,而 break 跳出不属于此列:

[9]:
s =  "Init"
for k in [1,2,3]:
    if k == 2:
        s = "Break"
        break
else:  # break 成功时将不会执行
    s = "End"
print(s)
Break

作为对比,如果循环语句中不含 break(或者 break 未被执行),那么 else 块能够正常执行:

[10]:
s =  "Init"
for k in [1,2,3]:
    if k > 10:
        s = "Break"
        break
else:
    s = "End"
print(s)
End

3.4.2. continue:跳过

continue 关键字来跳过当前的遍历项,开始遍历下一项。

[11]:
for k in [1, 2, 3]:
    if k == 2:
        continue
    print(k)
1
3

3.5. 循环语句工具

有一些函数非常适合用在循环语句中,可以简化语句的书写。这类工具包括:

  • range():在等差数列上循环

  • enumerate():循环时同时提供索引序数与项数据

  • zip():同时在循环多个序列

3.5.1. range() 函数:等差数列

函数 range() 用于生成“等差数列”,方便用户在循环语句中遍历数字:

  • range() 生成的并不是列表,而是一种名叫 range 的序列类型。它比列表更节省空间(因为只存储了首项、末项与公差),但一般地你可以将它视作一个列表。

其用法也非常简单:

  • range(start, stop, step) :生成一个首项为 start、末项为 stop、公差为 step 的等差数列

  • range(start, stop) :省略 step 参数时,默认公差为 1。

  • range(stop) :省略 start 参数时,默认首项从 0 开始。这是为了与长度为 stop 的序列的索引相吻合:0, 1, 2, …, n-1 。

[12]:
x = range(5)
for number in x:
    print(number)
0
1
2
3
4

另一个例子是,打印序列 x 的索引下标。这种用 range() 函数配合长度函数 len() 的使用是较为常见的。

[13]:
x = ["a", "c", "b"]
for i in range(len(x)):
    print(i)
0
1
2

你也可以将 range 类型强行转为列表类型,但通常这没有必要:

[14]:
print(list(range(5)))
[0, 1, 2, 3, 4]

一个稍微复杂点的例子,用循环语句计算一百以内所有奇数 1+3+5+…+99 的求和结果。当然,更简单的方法是直接对数字序列使用 sum() 函数来求和,两者的结果是一致的。

[15]:
s = 0
nums = range(1, 100, 2)
for number in nums:  # 或者 range(1, 99, 2)
    s += number
print(s, sum(nums))
2500 2500

3.5.2. enumerate() 函数:序数与值循环

枚举函数 enumerate() 能够让用户方便地对序列的索引序数进行操作。

一个应用场景是,打印列表中的第 i 项分别是什么。如果用朴素的按索引循环的写法:

[16]:
lst_with_a_long_name = ["apple", "banana", "orange"]

for i in range(len(lst_with_a_long_name)):
    print(i, "\t", lst_with_a_long_name[i])
0        apple
1        banana
2        orange

如果使用 enumerate() 函数,可以得到一种更为紧凑的写法——它在遍历时会返回一个二元的 (index, item) 元组,因此用户可以方便地将它拆分到两个循环变量中去。

[17]:
lst_with_a_long_name = ["apple", "banana", "orange"]

for i, item in enumerate(lst_with_a_long_name):
    print(i, "\t", item)
0        apple
1        banana
2        orange

如你所见,这在列表的变量名较长的时候尤其有意义,可以显著地提高循环语句内容的可读性。

3.5.3. zip() 函数:多序列并列循环

函数 zip() 将多个序列并在一起,并在遍历索引下标 i 时返回这些序列的第 i 项组成的元组:

  • 如果这些序列长度不同,以最短的为准。

[18]:
x = ["A", "B", "C"]
y = [10, 20, 30]
z = ["a", "b", "c", "d"]

for xi, yi, zi in zip(x, y, z):
    print(xi, yi, zi)
A 10 a
B 20 b
C 30 c