叶子带你学 Python | (二)程序结构
习题答案
作业一,代码如下:
print(1 + 1)
输出结果为”2“。
作业二,会抛出ZeroDivisionError
异常,提示不能将一个数除以零。
作业三,代码如下:
a = "简"
b = "书"
print(a + b)
输出结果为”简书“。在这段代码中,”+“的作用是将两个字符串连接起来。
如果你将 a 定义为 ”1“,b 定义为 ”2“,输出结果不是 ”3“,而是 ”12“,因为数字被双引号包裹着,它们本质上是字符串。
另外,如果你尝试在一个整数和一个字符串中间使用 ”+“,程序也会报错。
先谈谈 VS Code
在编写上一篇文章中的程序时,你可能会发现,在输入部分内容时,光标下方会出现一些候选项。
image这是 VS Code 的自动补全功能。它会搜索你程序中存在的所有变量名,并在你输入前半部分时,显示与之匹配的内容。这时,如果你按下 Enter 键,第一个候选项将会被输入。
在这张图中,第一个候选项是我们想要输入的 print,右侧显示的是 print 的函数文档,里面有它的完整用法。
其它几个候选项我们会在后文提到。
for 循环
现在,你已经学会了通过编写程序定义一个变量,并将其输出到屏幕上。
但如果我有一天突发奇想要写一篇水文,文章里无非就一百个”水“字,该怎么办?
难道定义一个”水“ 的字符串变量,然后写一百个 print 解决问题?
又或者定义一个有一百个”水“的字符串,然后用一个 print 输出?
不,太麻烦了。
所以我们需要一种方法,我们来写好每一次要执行的代码,并指定要执行多少次,让程序来完成重复劳动。
这就是循环结构。
针对上面的问题,我们可以编写这样一段程序来实现:
water = "水"
for i in range(100):
print(water)
有点复杂?没关系,慢慢来。
首先,我们定义了一个变量,之后使用了一个 for 关键字来告诉程序”我想要写一个循环“。因为有 for 关键字,所以这种循环被叫做“for”循环。
”关键字“其实是一些特殊的词,它们不是字符串,所以不需要使用双引号包裹。
另外,关键词不能用作变量名,比如你不能把一个变量叫做 ”for“,可以自己尝试一下。
接下来是一个空格,紧接着的”i“,我们把它称为”循环变量“。顾名思义,它也是变量,所以我们可以在这个循环中将其输出。
然后又是一个空格,”in“也是一个关键字,它在 Python 中有两种用法,其一是作为循环结构的一部分,另一种我们会很快学到。
之后是一个函数,是的,我们把 Python 中后面接括号的东西叫做”函数“。在 VS Code 的默认主题中,函数显示为黄色。函数内的”100“是它的参数,我们可以将其理解为循环 100 次。
之后是一个冒号。如果你自己输入这段代码,会发现在换行时光标并没有到下一行的开头,而是在略微靠右的位置。这是缩进,Python 通过缩进来判断哪段代码是循环的一部分。
缩进有两种,Tab 和空格。考虑到兼容性问题,建议大家使用空格,这也是 VS Code 中对缩进的默认设置。
在编程规范中,建议使用 4 个空格进行缩进,你可以通过手动输入 4 个空格或者按下键盘上的 Tab 键来实现缩进。
当你想要结束循环时,需要将缩进取消。编辑器不会帮你完成这一步,你需要手动按下退格键。正常情况下,按一次退格键就可以取消缩进。
现在运行程序,我们将看到程序输出了 100 个”水“,每个占一行。
现在,稍微改动一下程序,把”water“替换成”i“,就像这样:
water = "水"
for i in range(100):
print(i)
你可能会发现前面定义的”water“下方出现了黄色波浪线,这是编辑器的警告,提示你这个变量定义了,但没有被使用。尝试删除字符串后的引号,”水“的下方将出现红色下划线,这是错误。
所以,在运行程序之前,请先查看编辑器左下角的图标,确保错误和警告数量均为 0。警告在大多数情况下不会导致程序报错,但可能会让它的输出结果与你想的不同,所以不要忽略它。
将鼠标放在错误或警告上稍作停顿,可以看到错误的详细信息。我们会在后文讲到它们的含义。
现在运行你的程序。输出结果不是 100 个 100,而是从 0 开始,一直到 99 结束。
我们竟然在无意中做出了一个计数器!
为什么呢?其实 range 函数的参数 100,不仅意味着将循环执行 100 次,还会在每次循环之前,生成一个数,并将其作为前面循环变量 i 的值。
准确来说,从 0 开始生成,直到比参数小 1 的数停止。
如果大家好奇为什么不是从 1 开始,可以去搜索一下。
现在思考一个问题,怎么让程序从 1 开始输出,直到 100 结束呢?
答案是在 print 之前加上一行i = i + 1
,注意缩进哦。
这行代码将会在每次输出 i 的值之前,计算 i + 1 的值,并将其重新赋值给 i,改变它原有的值。
注意,在循环中改变循环变量的值不会影响 range 函数的工作,下次循环时 i 依然会遵循 range 的生成规律。
while 循环
现在你已经成功水了一篇文章,但你仍不满足,想要通过在文章下评论的方式提高阅读量,即使你知道这样做的效果微乎其微。
但水文是会被锁定的,锁定后你就不能发布评论了,为了避免做无用功,我们需要另外一种方式,在文章存在的时候不断发布评论,而文章不存在的时候什么也不做。
这段逻辑可以使用以下代码来表示:
while ArticleStatusNormal:
Commit()
这段代码是不能运行的,因为 ArticleStatusNormal 变量和 Commit 函数没有被定义,但这并不妨碍我们窥探它的运行原理。
这种循环的关键字是”while“,所以被叫做”while“循环,编程界的起名就是这么简单粗暴。while 循环没有循环变量,是不是比 for 循环简单?
这段代码将在循环开始时检测 ArticleStatusNormal 的值,如果为真则执行循环中的内容,如果为假则什么都不做。
这里需要引入另一个变量,叫做”布尔值“,其实就是”是“和”否“。
在 Python 中,我们使用关键字 True 定义真,False 定义假。
zhen = True
jia = False
True 和 False 是关键字,所以它们不需要用双引号包裹。大小写在这里是强制的,写成 true 和 false 将会报错。
现在,我们将代码改成这样:
ArticleStatusNormal = True
def Commit():
pass
while ArticleStatusNormal:
Commit()
我们在第一行定义了一个变量,其值为真。后面定义了一个函数,如你所见,函数内也是需要缩进的,不过我们暂时不需要理解它。
事实上,这个名为 Commit 的函数没有做任何事。真实的发布评论流程较为复杂,而且我们也不赞成水文行为,是吧?
现在运行程序,你会发现它没有输出任何东西,而且你无法停止它。不要慌,按下 Ctrl + C 强制终止程序。
你刚刚遇到了一个死循环。由于 while 函数判断的布尔值永远为真,所以程序会一直处于循环过程中。Ctrl + C 的作用是抛出一个异常来让程序报错退出。
if 语句
水了文,发了评论,心情舒畅,但你再次突发奇想,想要统计一下文章的阅读量情况,看看自己的水文大业进展如何。
话不多说,直接上代码,再提醒一遍注意缩进:
if GetArticleReadsCount() > 1000:
print("水文居然火了!")
else:
print("可惜了,没火")
这段代码也不能运行。
判断文章的阅读量,如果大于 1000 则输出”水文居然火了“,否则输出”可惜了,没火“。
if 和 else 也是关键字,这样的结构被叫做”分支“,就像考试成绩一样,100 分和 59 分的结果是互相独立的。
在同一个分支中,if 和 else 对应的代码块只有一个会被执行,函数并没有量子力学的特性,if 后的条件也不可能在真和假之间反复横跳。
那如果我想把文章分为”火“、”没火“和“0 阅读“三个等级呢?我们可以使用 elif 语句。
if GetArticleReadsCount() > 1000:
print("水文居然火了!")
elif 0 < GetArticleReadsCount() < 1000:
print("可惜了,没火")
else:
print("这么优秀的水文居然没人看!")
elif 其实是 else if 的缩写,其后面和 if 一样加上需要判断的条件。
程序执行时会自上而下依次判断,如果符合条件会进入,不符合条件则会继续寻找,如果所有条件都不匹配,则会执行 else 中的代码。
else 不是必须的。如果没有 else 语句,当所有条件都不匹配时,程序会跳过这一段,什么也不做。
课后作业
今天我们学习了两种循环结构和一种分支结构,所有的程序本质上都是循环和分支的不同组合。
作业一:给定场景:在有新评论时对评论进行回复,请问应该使用哪种结构?
作业二:请指出该程序中的错误:
if score < 90:
print("差一点就优秀了")
elif score < 60:
print("怎么会没及格呢?")
else:
print("优秀,继续加油!")
提示:考虑 if 语句的执行顺序,如没有思路可以定义不同的 score 值尝试一下。
作业三:请编写一段程序,输出 1 至 100 中所有的偶数。
提示:可以使用 % 获得余数,例如3 % 2
意味着 3 除以 2 的余数,结果等于 1。判断两个数相等使用两个等于号==
。