《Python编程快速上手——让繁琐工作自动化》——2.7 控制流语句

简介:

本节书摘来自异步社区《Python编程快速上手——让繁琐工作自动化》一书中的第2章,第2.7节,作者[美] Al Sweigart,王海鹏 译,更多章节内容可以访问云栖社区“异步社区”公众号查看。

2.7 控制流语句

现在,让我们来看最重要的控制流部分:语句本身。语句代表了在图2-1的流程图中看到的菱形,它们是程序将做出的实际决定。

2.7.1 if语句

最常见的控制流语句是if语句。if语句的子句(也就是紧跟if语句的语句块),将在语句的条件为True时执行。如果条件为False,子句将跳过。

在英文中,if语句念起来可能是:“如果条件为真,执行子句中的代码。”在Python中,if语句包含以下部分:

if关键字;

条件(即求值为True或False的表达式);

冒号;

在下一行开始,缩进的代码块(称为if子句)。

例如,假定有一些代码,检查某人的名字是否为Alice(假设此前曾为name赋值)。

if name == 'Alice':
    print('Hi, Alice.')

所有控制流语句都以冒号结尾,后面跟着一个新的代码块(子句)。语句的if子句是代码块,包含print('Hi, Alice.')。图2-3展示了这段代码的流程图。


09d746fdd97301a1bbaf398a28e53fe2b8b4937c

2.7.2 else语句

if子句后面有时候也可以跟着else语句。只有if语句的条件为False时,else子句才会执行。在英语中,else语句读起来可能是:“如果条件为真,执行这段代码。否则,执行那段代码”。else语句不包含条件,在代码中,else语句中包含下面部分:

else关键字;

冒号;

在下一行开始,缩进的代码块(称为else子句)。

回到Alice的例子,我们来看看使用else语句的一些代码,在名字不是Alice时,提供不一样的问候。

if name == 'Alice':
    print('Hi, Alice.')
else:
    print('Hello, stranger.')

图2-4展示了这段代码的流程图。


e936519eb09f6f26b14c1c4379286fb807100884

2.7.3 elif语句

虽然只有if或else子句会被执行,但有时候可能你希望,“许多”可能的子句中有一个被执行。elif语句是“否则如果”,总是跟在if或另一条elif语句后面。它提供了另一个条件,仅在前面的条件为False时才检查该条件。在代码中,elif语句总是包含以下部分:

elif关键字;

条件(即求值为True或False的表达式);

冒号;

在下一行开始,缩进的代码块(称为elif子句)。

让我们在名字检查程序中添加elif,看看这个语句的效果。

if name == 'Alice':
    print('Hi, Alice.')
elif age < 12:
    print('You are not Alice, kiddo.')

这一次,检查此人的年龄。如果比 12 岁小,就告诉他一些不同的东西。可以在图2-5中看到这段代码的流程图。

如果age < 12为True并且name == 'Alice'为False,elif子句就会执行。但是,如果两个条件都为False,那么两个子句都会跳过。“不能”保证至少有一个子句会被执行。如果有一系列的elif语句,仅有一条或零条子句会被执行。一旦一个语句的条件为True,剩下的elif子句会自动跳过。例如,打开一个新的文件编辑器窗口,输入以下代码,保存为vampire.py。

if name == 'Alice':
    print('Hi, Alice.')
elif age < 12:
    print('You are not Alice, kiddo.')
elif age > 2000:
    print('Unlike you, Alice is not an undead, immortal vampire.')
elif age > 100:
    print('You are not Alice, grannie.')


155c0c9563fc1d53f8e04a1f71186d17db4d8231

这里,我添加了另外两条elif语句,让名字检查程序根据age的不同答案而发出问候。图2-6展示了这段代码的流程图。

但是,elif语句的次序确实重要。让我们重新排序,引入一个缺陷。回忆一下,一旦找到一个True条件,剩余的子句就会自动跳过。所以如果交换vampire.py中的一些子句,就会遇到问题。像下面这样改变代码,将它保存为vampire2.py。

 if name == 'Alice':
     print('Hi, Alice.')
 elif age < 12:
     print('You are not Alice, kiddo.')
1 elif age > 100:
     print('You are not Alice, grannie.')
 elif age > 2000:
     print('Unlike you, Alice is not an undead, immortal vampire.')


eb2aa81d3b2a0444117ca5773aa03660ceb398f3

假设在这段代码执行之前,age变量的值是3000。你可能预计代码会打印出字符串'Unlike you, Alice is not an undead, immortal vampire.'。但是,因为age > 100条件为真(毕竟3000大于100)1,字符串'You are not Alice, grannie.'被打印出来,剩下的语句自动跳过。别忘了,最多只有一个子句会执行,对于elif语句,次序是很重要的。

图2-7展示了前面代码的流程图。请注意,菱形age > 100和age > 2000交换了位置。


2e793350c849b56d48f5afb37fb176f139792305

你可以选择在最后的elif语句后面加上else语句。在这种情况下,保证至少一个子句(且只有一个)会执行。如果每个if和elif语句中的条件都为False,就执行else子句。例如,让我们使用if、elif和else子句重新编写Alicee程序。

if name == 'Alice':
    print('Hi, Alice.')
elif age < 12:
    print('You are not Alice, kiddo.')
else:
    print('You are neither Alice nor a little kid.')

图2-8展示了这段新代码的流程图,我们将它保存为littleKid.py。


0226c5253ffa6225823e8e86d92f6f85259e5362

在英语中,这类控制流结构会使得:“如果第一个条件为真,做这个。否则,如果第二个条件为真,做那个。否则,做另外的事。”如果你同时使用这3个语句,要记住这些次序规则,避免图2-7中那样的缺陷。首先,总是只有一个if语句。所有需要的elif语句都应该跟在if语句之后。其次,如果希望确保至少一条子句被执行,在最后加上else语句。

2.7.4 while循环语句

利用while语句,可以让一个代码块一遍又一遍的执行。只要while语句的条件为True,while子句中的代码就会执行。在代码中,while语句总是包含下面几部分:

关键字;

条件(求值为True或False的表达式);

冒号;

从新行开始,缩进的代码块(称为while子句)。

可以看到,while语句看起来和if语句类似。不同之处是它们的行为。if子句结束时,程序继续执行if语句之后的语句。但在while子句结束时,程序执行跳回到while语句开始处。while子句常被称为“while循环”,或就是“循环”。

让我们来看一个if语句和一个while循环。它们使用同样的条件,并基于该条件做出同样的动作。下面是if语句的代码:

spam = 0
if spam < 5:
    print('Hello, world.')
    spam = spam + 1

下面是while语句的代码:

spam = 0
while spam < 5:
    print('Hello, world.')
    spam = spam + 1

这些语句类似,if和while都检查spam的值,如果它小于5,就打印一条消息。但如果运行这两段代码,它们各自的表现非常不同。对于if语句,输出就是"Hello, world."。但对于while语句,输出是"Hello, world."重复了5次!看一看这两段代码的流程图,图2-9和2-10,找一找原因。


c929ab86394c9a35df7b7b6006eb408fca92bbf6


10e5e52d0ec25e9c94c84847546f69ac9ab59255

带有if语句的代码检查条件,如果条件为True,就打印一次"Hello, world."。带有while循环的代码则不同,会打印5次。打印5次后停下来是因为,在每次循环迭代末尾,spam中的整数都增加1。这意味着循环将执行5次,然后spam < 5变为False。

在while循环中,条件总是在每次“迭代”开始时检查(也就是每次循环执行时)。如果条件为True,子句就会执行,然后,再次检查条件。当条件第一次为False时,while子句就跳过。

2.7.5 恼人的循环

这里有一个小例子,它不停地要求你输入“your name”(就是这个字符串,而不是你的名字)。选择FileNew Window,打开一个新的文件编辑器窗口,输入以下代码,将文件保存为yourName.py:

1 name = ''
2while name != 'your name':
     print('Please type your name.')
3     name = input()
4 print('Thank you!')

首先,程序将变量name1设置为一个空字符串。这样,条件name != 'your name'就会求值为True,程序就会进入while循环的子句2。

这个子句内的代码要求用户输入他们的名字,然后赋给name变量3。因为这是语句块的最后一行,所以执行就回到while循环的开始,重新对条件求值。如果name中的值“不等于”字符串'your name',那么条件就为True,执行将再次进入while子句。

但如果用户输入your name,while循环的条件就变成'your name' != 'your name',它求值为False。条件现在是False,程序就不会再次进入while循环子句,而是跳过它,继续执行程序后面的部分4。图2-11展示了yourName.py程序的流程图。


b17395a6d186515a725292f00ecfe090f9607d90

现在,让我们来看看yourName.py程序的效果。按F5键运行它,输几次your name之外的东西,然后再提供程序想要的输入。

Please type your name.
Al
Please type your name.
Albert
Please type your name.
%#@#%*(^&!!!
Please type your name.
your name
Thank you!

如果永不输入your name,那么循环的条件就永远为False,程序将永远问下去。这里,input()调用让用户输入正确的字符串,以便让程序继续。在其他程序,条件可能永远没有实际变化,这可能会出问题。让我们来看看如何跳出循环。

2.7.6 break语句

有一个捷径,让执行提前跳出while循环子句。如果执行遇到break语句,就会马上退出while循环子句。在代码中,break语句仅包含break关键字。

非常简单,对吗?这里有一个程序,和前面的程序做一样的事情,但使用了break语句来跳出循环。输入以下代码,将文件保存为yourName2.py:

1 while True:
     print('Please type your name.')
2    name = input()
3     if name == 'your name':
4         break
5 print('Thank you!')

第一行1创建了一个“无限循环”,它是一个条件总是为True的while循环。(表达式True总是求值为True。)程序执行将总是进入循环,只有遇到break语句执行时才会退出(“永远不”退出的无限循环是一个常见的编程缺陷)。

像以前一样,程序要求用户输入your name2。但是现在,虽然执行仍然在while循环内,但有一个if语句会被执行3,检查name是否等于your name。如果条件为True,break语句就会运行4,执行就会跳出循环,转到print('Thank you!') 5。否则,包含break语句的if语句子句就会跳过,让执行到达while循环的末尾。此时,程序执行跳回到while语句的开始1,重新检查条件。因为条件是True,所以执行进入循环,再次要求用户输入your name。这个程序的流程图参见图2-12。

运行yourName2.py,输入你为yourName.py程序输入的同样文本。重写的程序应该和原来的程序反应相同。


d3f32b5b9049cba08ad45dabca195f04e9e81b73

2.7.7 continue语句

像break语句一样,continue语句用于循环内部。如果程序执行遇到continue语句,就会马上跳回到循环开始处,重新对循环条件求值(这也是执行到达循环末尾时发生的事情)。

让我们用continue写一个程序,要求输入名字和口令。在一个新的文件编辑窗口中输入以下代码,将程序保存为swordfish.py。

 while True:
     print('Who are you?')
     name = input()
1     if name != 'Joe':
2        continue
     print('Hello, Joe. What is the password? (It is a fish.)')
3     password = input()
     if password == 'swordfish':
4         break
5 print('Access granted.')

如果用户输入的名字不是Joe1,continue语句2将导致程序执行跳回到循环开始处。再次对条件求值时,执行总是进入循环,因为条件就是True。如果执行通过了if语句,用户就被要求输入口令3。如果输入的口令是swordfish,break语句运行4,执行跳出while循环,打印Access granted5。否则,执行继续到while循环的末尾,又跳回到循环的开始。这个程序的流程图参见图2-13。

陷在无限循环中?

如果你运行一个有缺陷的程序,导致陷在一个无限循环中,那么请按Ctrl-C。这将向程序发送KeyboardInterrupt错误,导致它立即停止。试一下,在文件编辑器中创建一个简单的无限循环,将它保存为infiniteloop.py。

while True:
   print('Hello world!')

如果运行这个程序,它将永远在屏幕上打印Hello world!因为while语句的条件总是True。在IDLE的交互式环境窗口中,只有两种办法停止这个程序:按下Ctrl-C或从菜单中选择ShellRestart Shell。如果你希望马上停止程序,即使它不是陷在一个无限循环中,Ctrl-C也是很方便的。

运行这个程序,提供一些输入。只有你声称是Joe,它才会要求输入口令。一旦输入了正确的口令,它就会退出。

Who are you?
I'm fine, thanks. Who are you?
Who are you?
Joe
Hello, Joe. What is the password? (It is a fish.)
Mary
Who are you?
Joe
Hello, Joe. What is the password? (It is a fish.)
swordfish
Access granted.


e53992c39bbf94ea7350b7d287c7fcc864a0dcf3

2.7.8 for循环和range()函数

在条件为True时,while循环就会继续循环(这是它的名称的由来)。但如果你想让一个代码块执行固定次数,该怎么办?可以通过for循环语句和range()函数来实现。

“类真”和“类假”的值

其他数据类型中的某些值,条件认为它们等价于True和False。在用于条件时,0、0.0和' '(空字符串)被认为是False,其他值被认为是True。例如,请看下面的程序:

name = ''
while not name:1
print('Enter your name:')
name = input()
print('How many guests will you have?')
numOfGuests = int(input())
if numOfGuests:2
print('Be sure to have enough room for all your guests.')3
print('Done')

如果用户输入一个空字符串给name,那么while语句的条件就会是True 1,程序继续要求输入名字。如果numOfGuests不是0 2,那么条件就被认为是True,程序就会为用户打印一条提醒信息3。

可以用not name != ' '代替not name,用numOfGuests != 0代替numOfGuests,但使用类真和类假的值会让代码更容易阅读。

在代码中,for语句看起来像for i in range(5):这样,总是包含以下部分:

for关键字;

一个变量名;

in关键字;

调用range()方法,最多传入3个参数;

冒号;

从下一行开始,缩退的代码块(称为for子句)。

让我们创建一个新的程序,名为fiveTimes.py,看看for循环的效果。

print('My name is')
for i in range(5):
    print('Jimmy Five Times (' + str(i) + ')')

for循环子句中的代码运行了5次。第一次运行时,变量i被设为0。子句中的print()调用将打印出Jimmy Five Times (0)。Python完成for循环子句内所有代码的一次迭代之后,执行将回到循环的顶部,for语句让i增加1。这就是为什么range(5)导致子句的5次迭代,i分别被设置为0、1、2、3、4。变量i将递增到(但不包括)传递给range()函数的整数。图2-14展示了fiveTimes.py程序的流程图。


4b4d32a1d1bc5e4ea24fe7eb41269483426bdf8a

运行这个程序时,它将打印5次Jimmy Five Times和i的值,然后离开for循环。

My name is
Jimmy Five Times (0)
Jimmy Five Times (1)
Jimmy Five Times (2)
Jimmy Five Times (3)
Jimmy Five Times (4)

也可以在循环中使用continue语句。continue语句将让for循环变量继续下一个值,就像程序执行已经到达循环的末尾并返回开始一样。实际上,只能在while和for循环内部使用continue和break语句。如果试图在别处使用这些语句,Python将报错。

作为for循环的另一个例子,请考虑数学家高斯的故事。当高斯还是一个小孩时,老师想给全班同学布置很多计算作业。老师让他们从0加到100。高斯想到了一个聪明办法,在几秒钟内算出了答案,但你可以用for循环写一个Python程序,替你完成计算。

1total = 0
2for num in range(101):
3     total = total + num
4 print(total)

结果应该是5050。程序刚开始时,total变量被设为0。然后for循环执行100次total = total + num。当循环完成100次迭代时,0到100的每个整数都加给了total。这时,total被打印到屏幕上。即使在最慢的计算机上,这个程序也不用1秒钟就能完成计算。

(小高斯想到,有50对数加起来是100:1 + 99, 2 + 98, 3 + 97……直到49 + 51。因为50 × 100 是5000,再加上中间的50,所以0到100的所有数之和是5050。聪明的孩子!)

2.7.9 等价的while循环

实际上可以用while循环来做和for循环同样的事,for循环只是更简洁。让我们用与for循环等价的while循环,重写fiveTimes.py。

print('My name is')
i = 0
while i < 5:
    print('Jimmy Five Times (' + str(i) + ')')
    i = i + 1

运行这个程序,输出应该和使用for循环的fiveTimes.py程序一样。

2.7.10 range()的开始、停止和步长参数

某些函数可以用多个参数调用,参数之间用逗号分开,range()就是其中之一。这让你能够改变传递给range()的整数,实现各种整数序列,包括从0以外的值开始。

for i in range(12, 16):
    print(i)

第一个参数是for循环变量开始的值,第二个参数是上限,但不包含它,也就是循环停止的数字。

12
13
14
15

range()函数也可以有第三个参数。前两个参数分别是起始值和终止值,第三个参数是“步长”。步长是每次迭代后循环变量增加的值。

for i in range(0, 10, 2):
    print(i)

所以调用range(0, 10, 2)将从0数到8,间隔为2。

0
2
4
6
8

在为for循环生成序列数据方面,range()函数很灵活。举例来说,甚至可以用负数作为步长参数,让循环计数逐渐减少,而不是增加。

for i in range(5, -1, -1):
    print(i)

运行一个for循环,用range(5, -1, -1)来打印i,结果将从5降至0。

5
4
3
2
1
0
相关文章
|
6天前
|
数据采集 存储 API
网络爬虫与数据采集:使用Python自动化获取网页数据
【4月更文挑战第12天】本文介绍了Python网络爬虫的基础知识,包括网络爬虫概念(请求网页、解析、存储数据和处理异常)和Python常用的爬虫库requests(发送HTTP请求)与BeautifulSoup(解析HTML)。通过基本流程示例展示了如何导入库、发送请求、解析网页、提取数据、存储数据及处理异常。还提到了Python爬虫的实际应用,如获取新闻数据和商品信息。
|
7天前
|
安全 Java 数据处理
Python网络编程基础(Socket编程)多线程/多进程服务器编程
【4月更文挑战第11天】在网络编程中,随着客户端数量的增加,服务器的处理能力成为了一个重要的考量因素。为了处理多个客户端的并发请求,我们通常需要采用多线程或多进程的方式。在本章中,我们将探讨多线程/多进程服务器编程的概念,并通过一个多线程服务器的示例来演示其实现。
|
7天前
|
程序员 开发者 Python
Python网络编程基础(Socket编程) 错误处理和异常处理的最佳实践
【4月更文挑战第11天】在网络编程中,错误处理和异常管理不仅是为了程序的健壮性,也是为了提供清晰的用户反馈以及优雅的故障恢复。在前面的章节中,我们讨论了如何使用`try-except`语句来处理网络错误。现在,我们将深入探讨错误处理和异常处理的最佳实践。
|
1天前
|
API Python
Python模块化编程:面试题深度解析
【4月更文挑战第14天】了解Python模块化编程对于构建大型项目至关重要,它涉及代码组织、复用和维护。本文深入探讨了模块、包、导入机制、命名空间和作用域等基础概念,并列举了面试中常见的模块导入混乱、不适当星号导入等问题,强调了避免循环依赖、合理使用`__init__.py`以及理解模块作用域的重要性。掌握这些知识将有助于在面试中自信应对模块化编程的相关挑战。
6 0
|
2天前
|
Python
python面型对象编程进阶(继承、多态、私有化、异常捕获、类属性和类方法)(上)
python面型对象编程进阶(继承、多态、私有化、异常捕获、类属性和类方法)(上)
22 0
|
4天前
|
Web App开发 测试技术 网络安全
|
9天前
|
JSON 测试技术 持续交付
自动化测试与脚本编写:Python实践指南
【4月更文挑战第9天】本文探讨了Python在自动化测试中的应用,强调其作为热门选择的原因。Python拥有丰富的测试框架(如unittest、pytest、nose)以支持自动化测试,简化测试用例的编写与维护。示例展示了使用unittest进行单元测试的基本步骤。此外,Python还适用于集成测试、系统测试等,提供模拟外部系统行为的工具。在脚本编写实践中,Python的灵活语法和强大库(如os、shutil、sqlite3、json)助力执行复杂测试任务。同时,Python支持并发、分布式执行及与Jenkins、Travis CI等持续集成工具的集成,提升测试效率和质量。
|
缓存 Python 数据安全/隐私保护

热门文章

最新文章