5. 流程控制

在 Python 语言中,同样提供了现代编程语言都支持的两种基本流程控制结构:分支结构和循环结构。其中分支结构用于实现根据条件来选择性地执行某段代码,而循环结构则用于实现根据循环条件重复执行某段代码。

Python 使用 if 语句实现分支结构,通过 whilefor-in 语句实现循环结构,同时,还可以通过 breakcontinue 语句来控制程序的循环结构。

5.1. 顺序结构

在任何编程语言中最常见的程序结构就是顺序结构。顺序结构就是程序从上到下一行行地执行,中间没有任何判断和跳转。

如果 Python 程序的多行代码之间没有任何流程控制,则程序总是从上向下依次执行,排在前面的代码先执行,排在后面的代码后执行。这意味着如果没有流程控制,Python 程序的语句是 一个顺序执行流,从上向下依次执行每条语句。

5.2. if 分支结构

if 分支使用布尔表达式或布尔值作为分支条件来进行分支控制。Python 的 if 分支既可作为语句使用,也可作为表达式使用(已在第 2 章中的三目运算符介绍过)。

5.2.1. if 语句

if 语句可使用任意表达式作为分支条件来进行分支控制。Python 中的 if 语句有如下三种形式:

第一种形式:

if expression:
   statements ...

第二种形式:

if expression:
   statements ...
else:
   statements ...

第三种形式:

if expression:
   statements ...
elif expression:
   statements ...
   # 可以有零条或多条 elif 语句
else:
   statement ...
   # 可以有零条或一条 else 语句

对于上面的 if 分支语句,执行过程是非常简单的一一如果 if 条件为“真”,程序就会执行 if 条件后面的多条语句,否则就会依次判断 elif 条件,如果 elif 条件为“真”,程序就会执行 elif 条件后面的多条语句 …… 如果前面所有条件都为“假”,程序就会执行 else 后的代码块(如果有),使用方法如下代码所示:

s_age = input("请输入您的年龄:")
age= int(s_age)
if age > 18:
	print("已成年")
else:
	print("未成年")

运行上面代码,如果输入年龄大于 18 ,将会看到输出结果“已成年”,否则,输出“未成年”。从上述代码发现,在 if 条件语句中需要注意如下的三点:

  1. 代码块一定要缩进,否则就不是代码块
  2. 同一个代码块内的代码必须保持相同的缩进
  3. 不要遗忘条件语句后的冒号

5.2.2. if 条件的类型

Python 执行 if 语句时,会判断 if 条件是 True 还是 False。if 条件可以是任意类型,当下面的值作为 bool 表达式时,会被解释器当作 False 处理。

False, None, 0, ””, (), [], {}

从上面介绍可以看出,除了 False 本身,各种代表“空”的 None 、空字符串、空元组、空列表、空字典都会被当成 False 处理,以空字符串为例,使用方法如下代码所示:

s = "" # False
if s:
	print('s 不是空字符串')
else:
	print('s 是空字符串')

执行上述代码,最终的结果为“s 是空字符串”。

5.2.3. if 分支的逻辑错误

对于 if 分支,还有一个很容易出现的逻辑错误,这个逻辑错误并不属于语法问题,但引起错误的可能性更大,以下面的代码为例:

score = 90
if score >= 60:
	print("及格")
elif score >= 75:
	print("良好")
elif score >= 90:
	print("优秀")
else:
	print("不及格")

在执行代码前,希望最终程序的输出为“优秀”,但是执行代码后输出的却是“及格”,这里面存在一个逻辑错误,出现这个问题主要的原因是 if 条件之间存在重叠,修改方案是要使得 if 条件之间不再重叠,如下代码所示:

score = 90
if score >= 60 and score < 75:
	print("及格")
elif score >= 75 and score < 90:
	print("良好")
elif score >= 90:
	print("优秀")
else:
	print("不及格")

执行代码,最终符合逻辑,输出“优秀”。

5.2.4. pass 语句

要实现“空语句”,即什么也不操作也不做的语句, Python 中提供了 pass 语句实现空语句。通过使用 pass 语句,主要的作用是让程序看起来更加完整,使用方法如下代码所示:

a = input("请输入一个整数 :")
a = int(a)
if a > 5
	print("大于 5 ")
elif a < 5:
	# 空语句,相当于占位符
	pass
else:
	print("等于 5")

如上代码,在大于 5 和等于 5 的情况下,都有对应的操作,即调用 print() 方法,为了保持代码的完整性,因此在小于 5 的情况下,采用空语句 pass 语句。

5.3. 断言

断言语句和 if 分支有点类似,它用于对一个 bool 表达式进行断言,如果该 bool 表达式为 True,该程序可以继续向下执行,否则程序会引发 AssertionError 错误。具体使用方法如下代码所示:

age= input("请输入您的年龄:")
age = int(age)
# 通过 assert 保证年龄的合法性
assert 0 < age < 100
print("输入的年龄为:", age)

当输入为 40 时,可输出结果“输入的年龄为: 40”,若输入为 101,则报 AssertionError 错误。

5.4. 循环结构

循环语句可以在满足循环条件的情况下,反复执行某一段代码,这段被重复执行的代码被称为循环体 。当反复执行这个循环体时,需要在合适的时候把循环条件改为假,从而结束循环,否则循环将一直执行下去,形成死循环。循环语句可能包含如下 4 个部分:

  • 初始化语句:一条或多条语句,用于完成一些初始化工作。初始化语句在循环开始之前执行
  • 循环条件:这是一个布尔表达式,这个表达式能决定是否执行循环体
  • 循环体:这个部分是循环的主体,如果循环条件允许,这个代码块将被重复执行
  • 迭代语句:这个部分在一次执行循环体结束后,对循环条件求值之前执行,通常用于控制循环条件中的变量,使得循环在合适的时候结束

5.4.1. while 循环

while 循环的语法格式如下:

[init_statement]
while expression:
	statements
	[iteration statements]

while 循环在每次执行循环体之前,都要先对 expression 循环条件求值,如果循环条件为真,则运行循环体部分。while 循环的使用方法如下代码所示:

a = 1
sum = 0
while a < 10:
	sum += a
	a += 1
print(sum) # 45

由于列表和元组的元素都是有索引的,因此可通过 while 循环遍历列表或元组中的所有元素,具体使用方法如下代码所示:

# 遍历 list
list_a = list(range(10))
i = 0
while i < len(list_a):
	print(list_a[i])
	i += 1
# 遍历 tuple
tuple_a = tuple(range(10))
j = 0
while j < len(tuple_a):
	print(tuple_a[j])
	j += 1

5.4.2. for-in 循环

for-in 循环专门用于遍历范围、列表、元组和字典等可迭代对象包含的元素。for-in 循环的语法格式如下:

for 变量 in 字符串|范围|集合等:
	statements

for-in 循环中的变量完受 for-in 循环控制,因此该变量也被称为循环计数器。for-in 循环可用于任何可迭代对象,可迭代对象就是指该对象中包含一个 __iter__ 方法,且该方法的返回值对象具有 next() 方法。for-in 循环的使用方法的代码如下所示:

list_a = list(range(10))
print(list_a) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# for-in 循环
list_b = []
for x in list_a:
	list_b.append(x * 2)
print(list_b) # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

上述代码演示了 for-in 循环遍历列表中的元素,列表中有几个元素,for-in 循环的循环体就执行几次,针对每个元素执行一次,循环计数器会依次被赋值为元素的值。除了可以循环遍历列表,同样还可以循环遍历元组,范围以及字典,具体的代码如下所示:

# 遍历范围
for x in range(10):
	print(x)

# 遍历元组
tuple_a = tuple(range(10))
for x in tuple_a:
	print(x)

# 遍历字典
dict_a = {"name":"felixzhao", "gender":"male", "age":33}
'''
name -> felixzhao
gender -> male
age -> 33
'''
for key, value in dict_a.items():
	print(key + " -> " + str(value))

5.4.3. 循环使用 else

Python 的循环都可以定义 else 代码块,当循环条件为 False 时,程序会执行 else 代码块。使用方法的代码如下所示:

i = 0
while i < 5:
	print("循环中,当前的值为:i = ", i)
	i += 1
else:
	print("循环外,当前的值为:i = ", i)

上述代码的执行结果为:

循环中,当前的值为:i =  0
循环中,当前的值为:i =  1
循环中,当前的值为:i =  2
循环中,当前的值为:i =  3
循环中,当前的值为:i =  4
循环外,当前的值为:i =  5

可见,当不满足循环条件后,会执行 else 中的执行语句。

5.4.4. 嵌套循环

如果把一个循环放在另一个循环体内,那么就可以形成嵌套循环。当程序遇到嵌套循环时,如果外层循环的循环条件允许,则开始执行外层循环的循环体,而内层循环将被外层循环的循环体来执行。当内层循环执行结束且外层循环的循环体也执行结束后,将再次计算外层循环的循环条件,决定是否再次开始执行外层循环的循环体。

以 9 x 9 乘法口诀表为例,其实现代码如下所示:

i, j = 1, 1
while j <= 9:
	while i <= j:
		a = str(i) + " X " + str(j) + " = " + str(i*j)
		print(a, end=' ')
		i += 1
	print() # 换行
	i = 1 # 重置 i
	j += 1

最终执行完的结果为:

输入图片说明

5.4.5 for 表达式

for 表达式用于利用其他区间、元组、列表等可迭代对象创建新的列表。for 表达式的语法格式如下所示:

[表达式 for 循环计数器 in 可迭代对象]

for 表达式最终返回的是列表,因此 for 表达式也被称为列表推导式,使用方法如以下代码所示:

range_a = range(10)
# 对 range_a 执行 for 表达式
list_a = [x * x for x in range_a]
# list_a 集合包含 10 个元素
print(list_a) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

还可以在 for 表达式后面添加 if 条件,这样 for 表达式将只迭代那些符合条件的元素,使用方法如下代码所示:

range_a = range(10)
# 对 range_a 执行 for 表达式,仅操作偶数
list_b = [x * x for x in range_a if x % 2 == 0]
# list_b 集合包含 5 个元素
print(list_b) # [0, 4, 16, 36, 64]

如果将 for 表达式的方括号 [] 改为圆括号 ()for 表达式将不再生成列表,而是生成一个生成器( generator ),该生成器同样可使用 for 循环迭代,使用方法如下代码所示:

range_a = range(10)
# 使用 for 表达式创建生成器
c_generator = (x * x for x in range_a if x % 2 == 0)
# 使用 for 循环迭代生成器
for i in c_generator:
	print(i, end='\t') # 0 4 16 36 64
print()

for 表达式还可以使用多个循环,就像嵌套循环一样,使用方法如下代码所示:

list_a= [(x, y) for x in range(2) for y in range(3)]
# list_a 列表包含 6 个元素
print(list_a) # [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)]

上述的 for 表达式相当于如下嵌套循环:

list_b = []
for x in range(2) :
	for y in range(3):
		list_b.append((x, y))
print(list_b) # [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)]

5.4.6. 常用工具函数

zip() 函数可以把两个列表“压缩”成一个 zip 对象,且时一个可迭代对象,这样就可以使用一个循环并行遍历两个列表,使用方法如下代码所示:

a = ['a', 'b', 'c']
b = [1, 2, 3]
# 并行遍历列表 a 和列表 b
c = [x for x in zip(a , b)]
print(c) # [('a', 1), ('b', 2), ('c', 3)]

从上述代码的执行结果来看,zip() 函数压缩得到的可迭代对象所包含的元素是由原列表元素组成的元组。如果原先的两个列表长度不一致,则以长度短的列表为准,如下代码所示:

a = ['a', 'b', 'c']
b = [0.1, 0.2]
# 以短的列表 b 为准
c = [x for x in zip(a, b)]
print(c) # [('a', 0.1), ('b', 0.2)]

reversed() 函数可以对各种序列进行反向遍历,如元组,列表,区间等,返回一个“反序排列”的迭代器,使用方法如下代码所示:

a = range (10)
b = [x for x in reversed(a)]
print(b) # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

sorted() 函数可以对各种可迭代对象排序,返回一个对元素排序的列表,使用方法如下代码所示:

import random

list_a = []
for i in range(10):
	list_a.append(random.randint(1, 100))
print(list_a) # [18, 23, 21, 68, 78, 69, 79, 26, 50, 10]

list_b = sorted(list_a)
print(list_b) # [10, 18, 21, 23, 26, 50, 68, 69, 78, 79]

在使用 sorted() 函数时,还可传入一个 reverse 参数,如果将该参数设置为 True ,则表示反向排序,使用方法如下代码所示:

list_a = [18, 23, 21, 68, 78, 69, 79, 26, 50, 10]
list_b = sorted(list_a, reverse=True)
print(list_b) # [79, 78, 69, 68, 50, 26, 23, 21, 18, 10]

在调用 sorted() 函数时,还可传入一个 key 参数,该参数可指定一个函数来生成排序的关键值,使用方法如下代码所示:

list_a = ['Ruby', 'Go', 'Swift', 'Kotlin', 'Erlang', 'Python']
list_b = sorted(list_a, key=len)
print(list_b) # ['Go', 'Ruby', 'Swift', 'Kotlin', 'Erlang', 'Python']

如上代码是根据字符串的长度排序。

5.5. 控制循环结构

为了控制循环的执行流程,在 Python 中提供了 continuebreak 语句来控制循环结构,除此之外,使用 return 语句可以结束整个方法。

5.5.1. 使用 break 结束循环

在一个特定的循环中,当某种条件出现时,需要强行中止循环,而不是等到循环条件为 Fa lse 时才退出循环,此时可以使用 break 语句来完成这个功能。break 用于完全结束一个循环,跳出循环体,使用方法如下代码所示:

a = []
for i in range(10):
	if i == 5:
		break # 当 i = 5 时,直接退出
	a.append(i)
print(a) # [0, 1, 2, 3, 4]

从上述代码可以发现,当 i = 5 时,直接就退出了循环中后续代码的执行,退出循环体。当在多层循环体中使用 break 语句时,退出当层的循环体,执行该层循环体后的代码,使用方法如下代码所示:

a = []
for i in range(5):
	for j in range(5):
		if j == 2:
			break # 当 j = 2 时,直接退出
		a.append((i, j))
# [(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1), (3, 0), (3, 1), (4, 0), (4, 1)]
print(a)

如上代码,当内层循环遇到 j = 2 时退出当层循环,执行该层循环体外的代码,即继续执行外层循环。

5.5.2 使用 continue 忽略本次循环的剩下语句

continue 语句的功能和 break 语句有点类似,区别是 continue 语句只是忽略当次循环的剩下语句,接着开始下一次循环,并不会中止循环,而 break 语句则是完全中止循环本身,使用方法如下代码所示:

a = []
for i in range(10):
	if i % 2 != 0:
		continue
	a.append(i) # 保存偶数
print(a) # [0, 2, 4, 6, 8]

从上述代码中可以看出,每当 i 为奇数时,不再执行循环体中剩下的代码,继续执行下一轮的循环。

5.5.3. 使用 return 结束方法

return 语句用于直接结束循环或者方法。在 Python 程序中一旦遇到 return 语句,直接从当前的方法中退出,无论 return 语句处在多少层循环之内,使用方法如下代码所示:

def get():
	for i in range(10):
		if i % 2 != 0:
			return
		print(i)
get()

5.6. 本章小结

本章主要介绍了 Python 中的流程控制,包括顺序结构,分支结构和循环结构。通过 if 条件语句能够实现分支结构,而在循环结构中,可以使用 while 循环语句或者 for-in 循环语句。为了改变循环结构,可以使用 break 语句或者 continue 语句,两者的区别是 break 语句结束循环本身,而 continue 语句则是忽略当次循环的剩下语句,接着开始下一次循环,并不会中止循环。

本章需要掌握知识点:

  1. if 条件语句的基本结构
  2. while 循环语句的基本结构
  3. for-in 循环语句的基本结构
  4. breakcontinue 改变循环结构