在上一篇文章中,我们所操作的所有代码都是顺序执行的。什么意思呢?就是我们在所有例子中的代码,计算机都是从第一句开始执行,执行完毕后执行第二句,以此类推,最终执行完整个代码块。
以下面代码为例:
print("First Line!")
print("Second Line!")
print("Third Line!")
输出结果:
First Line!
Second Line!
Third Line!
从结果可以看到,输出的内容顺序和我们写的代码顺序是一样的。像这种顺序执行的代码结构,称为顺序结构,是最普通的一种执行结构。在 Python 中,我们编写的代码默认以顺序结构执行。
顺序结构理解起来比较简单,但却不能满足所有场景的要求。
比如根据学生的考试成绩进行分析。
目前有以下两个任务。
考试成绩如果大于 80 分,则打印“优秀”;如果是 60 到 80 之间,则打印“及格”;小于 60 分,则打印“不及格”。
所有的学生的成绩,都需按 1 中所提到的方式打印出分级的结果。
上述的两个场景中,一个是需要选择性地执行部分代码,再一个是需要把同一段代码重复执行多次。这两个诉求,顺序结构无法满足。所以在 Python 中,会有分支结构和循环结构来处理类似上面的场景,这也是本篇文章内容-如何控制代码的执行顺序。
分支结构和循环结构,整个原理比较考验逻辑性,对于初次接触编程的人可能会有点不适应,不过不用担心,认认真真想几遍往往都能豁然开朗。从另一方面看,学 Python 还能提升自己的逻辑性和逻辑思维能力,不要太美。
分支结构,简单来说就是如果满足某个条件,则执行某块代码,否则就不执行。
在 Python 中用 if 语句来实现分支结构,形式是这样的。
if 条件:
代码块
我们来逐一剖析下上述代码块的关键要素。
回顾一下我们前言面的问题,拿到一个学生的考试成绩:
我们现在用 if 语句,来实现第一部分:如果大于 80 分,则打印“优秀”。
打开 VSCode, 创建一个新的 Notebook,并输入以下代码。
a = 90
if a > 80 :
print("优秀")
print("code finished")
上述代码中,主要由三部分组成:
上述代码输出结果如下:
优秀
code finished
为了测试在不满足条件时是否还会输出“优秀”,我们可以将 90 改为 75,再次运行程序。可以看到,这次的输出为 :
code finished
if 语句有几种形式,刚才我们学习的是最基础的形式,只有一个代码块,表示的是“如果满足条件,那么就做这件事”。
如果要表达的是:“如果满足条件,那么就做这件事,否则就做那件事”。可以看出新的形式里有“两件事”,所以会有两个代码块。这种形式叫作 if-else 语句(else 就代表上面描述里面的 “否则”),其实回想我们的生活中,绝大多数选择都是 if-else 结构的。
例如:当你出门的时候,你女朋友跟你说,买个西瓜回来,如果没有,就买一个哈密瓜。用 if-else 的接过来理解的话就是:“如果有西瓜,那么就买西瓜,否则就买哈密瓜”。
if-else 语句形式,是这样的。
if 条件:
代码块1
else:
代码块2
相比 if 语句, if-else 语句的关键要素增加了以下部分:
上述的例子中,我们实现了如果分数大于 80 则打印优秀,现在我们加一下需求:如果分数大于 80 则打印优秀,否则打印及格。
在刚才的 Notebook, 新建代码 Cell,输入以下代码:
a = 75
if a > 80 :
print("优秀")
else:
print("及格")
print("code finished")
执行之后输出如下。
及格
code finished
可以看到,当条件不满足时(75 < 80), if 控制的代码块没有执行,而 else 控制的代码块被执行了。
接下来,我们再看 if 语句的最后一种形式,就是在 if-else 中间再加了一个 elif(其实就是 else if 的简写),它的语句形式是这样的。
if 条件1:
代码块1
elif 条件2:
代码块2
...
else:
代码块N
从这个结构基本可以猜出来这个语句是做什么事情:如果满足条件 1,则执行代码块 1,否则看是否满足条件 2,满足则执行代码块 2,不满足则看是否满足条件 3,……如果所有条件都不满足,则执行最后由 else 控制的代码块。
if-elif-else 语句要关注以下几个关键点:
现在我们再次看一下,我们上面问题:拿到考试成绩,如果大于 80 分,则打印“优秀”;如果是 60 到 80 之间,则打印“及格”;小于 60 分,则打印“不及格”。
实操开始,新建 Cell,输入代表以上意思的代码,你先根据自己理解写,写完再看示例。哪怕暂时不知道怎么写,也要先想一下,这一步至关重要,先想一下能够大幅提升学习的效率。
a = 75
if a > 80:
print("优秀")
elif a > 60:
print("及格")
else:
print("不及格")
print("code finished")
上述代码执行的逻辑是:
这个例子还反映了一个 if 家族语句的重要特性:在一个 if-else 或者 if-elif-else 语句中,不管最后有多少个代码块,每次运行最终只会执行其中一个。 执行的是哪个呢?就是第一个符合条件的,拿上面的例子来说,a = 75,首先“是否大于 80”,明显是不满足的,所以继续看第二个条件:“是否大于 60”, 这里满足了。所以“是否大于 60”这个条件就是第一个符合条件的分支,所以其对应的代码块 print(“及格”)被执行。执行完毕后,便退出了整个 if 语句,下一步便执行了最后的打印 code finished 的语句。
为了验证我们的分支逻辑是否有效,我们给变量 a 分别赋值不同的分数值,比如 93、40、75 等,代码运行后,可以看到最终结果输出了对应的标签,比如以 75 分为例,结果输出为及格。
及格
code finished
至此,我们已经了解完了 Python 中实现分支结构的关键要素(if 家族语句)。
现在咱们来看看代码结构的另外一个重要分支:循环结构。顾名思义,循环结构实现的就是重复执行同一个代码块多次,在很多场景都非常重要。基本上所有统计逻辑:均值、方差等背后,都是通过循环结构来实现的。
比如写了一段分析单个用户下单习惯的数据分析代码,但你拿到的数据集里面有 10 万个用户,咱们肯定是不能一个个弄,横竖都弄不完,这里就需要一个强大的批量执行工具,也就是循环语句。
先从一个简单的场景开始思考,假设我们要打印三次:重要的事情说三遍。按照目前介绍到的语法,最直接的就是直接写三次 print 语句。
print("重要的事情说三遍")
print("重要的事情说三遍")
print("重要的事情说三遍")
输出结果如下:
重要的事情说三遍
重要的事情说三遍
重要的事情说三遍
代码不难理解,但也显得非常冗余,是否有更好的方式呢?
for 语句是 Python 实现循环的方式之一,也是最常用的方式,语句形式是这样的。
for 循环变量 in range(开始值,结束值,步长):
代码块
结构看起来比较复杂,但其实形式比较固定,我们来看看其中的几个关键元素。
这个结构做了一件什么样的事情呢?用白话来说就是,从循环变量=开始值开始,循环执行代码块,每次执行,循环变量的值都+步长,当循环变量的值大于或者等于结束值的时候,退出循环。
我们通过代码举例来理解。
for i in range(1,10,1):
print(i)
在这个例子里,循环变量 = i,开始值 = 1, 结束值 = 10, 步长 = 1。
结合我们的上面的描述,这个循环的逻辑就是变量 i 从 1 开始循环,每次 +1, 当超过 10 时停止,所以循环一共会执行 9 次,每次循环的代码块都会打印变量 i 的值。
我们运行代码后可以看到这样的输出结果。
1
2
3
4
5
6
7
8
9
如果我们把步长改成 2 会怎么样呢?按照刚才的说明,则是变量从 1 开始,每次 +2, 当大于 10 的时候退出循环,听起来是不是会导致循环次数减半?我们来验证一下,代码如下。
for i in range(1,10,2):
print(i)
输出结果确实如我们预期,只循环了五次,并且每次 i 都会 +2。
1
3
5
7
9
在我们日常写的代码中,最常用的步长就是 1,对于步长为 1 的循环,可以不写步长,因为 for 循环语句默认的步长就是 1,所以刚才第一个例子,我们也可以简写为这样。
for i in range(1,10):
print(i)
了解了循环的语法后,我们来尝试计算一个经典问题,计算 1+2+3…+99+100。当初高斯通过取巧的方式快速计算出了结果,现在我们尝试使用 Python 来实现。
问题分析:我们需要计算 100 个数的和,这么多数显然是不能都写出来的,回过头看刚才我们循环打印的值,可以发现,其实我们通过循环,可以让一个变量从 1 循环到 100,每次 +1。然后我们只需要在循环的代码块中把循环变量都加起来,就可以得到结果。
另外,还有一点需要注意,因为需要加到 100,而我们判断是否退出循环的标准是:循环变量是否大于等于结束值,所以我们循环的结束值应该是 101。
新建 Cell,输入如下代码。注意在这个例子里,因为我们需要累加,所以需要声明一个新的变量,我们命名为 result。
result = 0
for i in range(1,101):
result = result + i
print(result)
输出如下:
5050
可以看到,我们用 Python 计算的结果和高斯计算的结果是一样的。
Python 还有另一种实现循环的语句——while 语句,相比 if 语句形式上更简单,也更通用。它的语句形式是这样的。
while 循环条件:
代码块
关键要素主要有这两个。
while 语句的核心流程就是,当条件为真时,不断循环执行代码块,直到条件为假。这里的 while 其实翻译过来,就是 “当”的意思。
现在,我们尝试用 while 语句来实现一下刚才计算 1+2+3+…+100 的问题。
问题分析:刚刚我们用 for 循环来计算这个问题的实现方式,是用一个变量 result 来累加循环变量 i 的值,然后指定循环变量 i 从 1 循环到 100 即可。这样第一次循环,i 是 1,第二次循环 i 是 2,以此类推。
这次我们用 while,没有了循环变量,没有东西给我们累加到 result 上了,怎么办呢?我们可以自己声明一个普通的变量,这个变量随着循环的次数增加,值也相应增加。类似上面的 i,第一次循环是 1,第二次循环是 2…一直到第 100 次循环是 100,具体在 while 循环中实现这个过程,我们只要在代码块中每次给这个变量 +1,然后再把这个变量持续累加到 result 变量即可。
然后当循环变量超过 100 时,退出循环,那么我们可以用 上述变量 < 101 作为循环条件。
我们来实操下,新建 Cell ,输入如下代码:
i = 0
result = 0
while i < 101:
result = result + i
i = i + 1
print(result)
输出如下,可以看到,和 for 语句实现的版本是一致的。
5050
这个部分有点绕,不用着急,多看多想几次,再对比上面 for 循环的实现,就能理解。
大家看到 while 语句的形式就会想到一个问题,如果条件一直都为 True,那循环不是永远退不出来了?确实存在这种现象,在 Python 中,我们把这种循环一直无法退出的现象称之为:死循环。
死循环会导致程序执行卡死,因为一直在执行循环无法退出。所以在日常编程中,我们都需要尽量避免死循环,保证每个循环的退出条件都是可以达到的。
要测试死循环很简单,新建 Cell,输入如下代码
while 1 < 2:
print("dead loop")
因为 1 永远小于 2,所以这段代码执行之后会无限输出 dead loop,在 Notebook 中执行如下所示,(注意左边的执行标志一直是 * 号,代表一直未执行完毕)。
从条件入手,保证写了合适的条件之外,有没有其他避免死循环的方式呢?答案是肯定的,Python 的循环中有两种特殊的语句,用于终止循环。一种是 break 语句,用来终止整个循环。一种是 continue 语句,用于跳过当次循环。
(1)break 语句:结束当前整个循环语句的执行,转而执行循环语句后面的代码
以下面的代码为例:
for i in range(1,10):
print("Hello")
print(i)
print("loop finished")
根据 for 语句的定义,我们不难知道这段代码将会循环 9 次,每次都打印 Hello 和对应的循环变量的值,并在循环结束之后打印 loop,如下所示。
Hello
1
Hello
2
Hello
3
Hello
4
Hello
5
Hello
6
Hello
7
Hello
8
Hello
9
loop finished
我们在两个打印中间插入一个 break 语句,将代码改成这样,会发生什么事情呢?
for i in range(1,10):
print("Hello")
break
print(i)
print("loop finished")
从结果上看,代码只打印了一次 Hello 便打印了 loop finished,甚至一次都没有打印变量 i 的值。这说明在循环内的代码块中遇到 break 时,会马上结束整个循环语句的执行,转而执行循环语句后面的代码。在这个例子里面,也就是打印 loop finished。
(2)continue 语句:结束当次循环的执行,转而执行下一次循环。
注意 continue 和 break 的区别,break 是结束整个循环语句的执行,而 continue 只是结束当次循环的代码块,并不会退出循环语句。我们可以基于上述例子的代码来理解,如果将上面的代码的 break 换成 continue:
for i in range(1,10):
print("Hello")
continue
print(i)
print("loop finished")
输出结果如下:
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
loop finished
可以看到,打印了 9 次 hello,之后打印了 loop finished,同样一次都没有打印变量 i。原因就是每次执行循环代码块,执行到 continue 时,退出了当前代码块的执行(也就是没有执行到打印变量 i 这一句),执行了下一次循环,所以还是正常循环了 9 次。
break 与 continue 语句在 for 循环和 while 循环中的作用都是一样的