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