控制流又叫做流程控制,就是根据具体情况来控制程序,执行某些特定的程序块。Python的流程控制语句包括if条件语句、while循环语句和for循环语句。其中还细分为range函数、break、continue、pass等内部流程的控制语句。下面就来详细说说它们的用法。
if语句是最常用的条件控制语句,关键字有if、elif、else。一般的表述形式为:
if条件一:
statements1
elif条件二:
statements2
else:
statements3
意思是如果满足条件一,就执行statements1的代码;如果不满足条件一且满足条件二,就执行statements2的代码;如果条件一和条件二都不满足,就执行statements3的代码。
这里的条件一、条件二、条件三分别表示三个条件判断语句。当条件判断语句返回值为True时,就代表满足该条件。例如:
a= 4 #定义变量a的值为4
b= 5 #定义变量a的值为4
ifa>b: #当a大于b时,令c等于a的值;否则c等于b的值
c = a
else:
c = b
print(c) #将c显示。输出:5
在上面代码中,先比较a与b的值,当满足a大于b的条件,就会执行c等于a的语句。于是将a的值赋给了c,输出的结果为5。
注意:
上面的代码中,if与else部分还有个简化的写法,即,c = [a,b][a
这种由两个中括号组成的语法,完整的意思为:
如果第二个中括号里的条件值为假,则返回第一个中括号中的第一个元素;如果第二个中括号里的条件值为真,则返回第一个中括号中的第二个元素。
While是用来表述一个循环执行的代码流程,语句的形式为:
while条件一:
statements1
该语句的意思如下:
(1) 先执行条件一判断语句,看是否返回为True;
(2) 如果返回True,则执行下面的statements1代码;
(3) 执行完statements1的代码后,在回到(1),
(4) 如果(1)返回False,则整个语句结束。
statements1属于while的子代码块,每一行的开头都需要缩进。
Python中的for语句与while语句都是用来表述一个循环执行的代码流程。for的循环条件不是一个判断语句,而是一个序列容器的遍历。表述形式为:
foritem in 序列数据:
statements1
意思是,每次从序列容器中取一个值(item),然后执行语句statements1。当遍历完整个序列容器,整个循环也就结束了。
序列容器可以是任何Python支持的序列数据类型。如果在循环体内,执行语句statements1对for后面的序列数据进行了修改,这会影响到for语句的初始循环次数。
一般的避免方法是:使用切片的方法为该序列数据做一个副本,让for来遍历副本中的序列数据,这样statements1语句即使修改了对原始的序列容器中的数据,也不会影响到初始的循环次数了。例如:
words= ['I','love','Python'] #定义一个列表
foritem in words[:]: #for后面没有使用words,而是使用了切片作为words的副本
words.insert(0, item) #向words里插入一个元素
print(item) #打印item,三次迭代分别输出:'I'、 'love'、 'Python'
print(words) #打印整个words,输出:['Python', 'love', 'I', 'I','love', 'Python']
上面代码中的第二行使用了words的切片作为副本,完成了三次迭代(因为有三个元素,每个元素迭代一次)。)
再来看一个错误的写法。假如不使用副本,将第二句代码换成:
foritem in words:
这将会带来死循环。因为每次从words中遍历一个数据,执行下面语句时,就会为words添加一个数据。这样永远也无法将words中的数据遍历完。注意,一定要避免这种错误的写法。
在for循环中,还可以使用内置函数range来遍历一个数字序列。关于range的用法如下:
range的意思是返回一个数字区间的所有整数。需要说明的是,单独的print(rang(5))打印不出来从0到5之间的数字。输出的是“range(0, 5)”,代表从0到5的一个范围。
如果要想将其内容散列出来,可以将其转化成list类型,再打印出来,例如:
print(list(range(5))) #将0到5间的整数转化成list类型,并打印出来。输出:[0, 1, 2, 3, 4]
range中的参数默认是从0开始。上例中, range的参数5是代表从0到5之间的数。这里0到5区间的取值仍然与切片的取值一致,即,要头不要尾。意思就是0到5区间的数包含起始值(0),但是不包含结束值(5)。如果将比0小的数传入range,会打印不出内容。例如:
print(list(range(-5))) #-5比0小,range找不到任何比0大的数,只能返回空。输出:[]
这种情况下,可以通过指定个起始值,来将-5到0之间的数打印出来。例如:
print(list(range(-5,0))) #将-5到0间的整数转化成列表类型,并打印出来。输出:[-5, -4, -3,-2, -1]
上例中,range里面的第一个参数-5就代表起始值,第二个参数0就代表结束值。
range函数中还可以有第三个参数,代表步长。即,从起始到结束,每隔步长个数字返回一次。例如:
print(list(range(-5,0,2))) #将-5到0间每隔2个数取出一个,并转化成list类型,打印出来。输出:[-5, -3, -1]
了解完range后,再来看一个range与for组合的例子:
fori in range(5): #循环遍历0到5之间的整数
print(i) #将取出的值打印出来
这样就实现了循环5次的控制。用range中放置个整数(5)的方式,可以实现指定代码的具体循环次数。上例执行后,输出:
0
1
2
3
4
for语句还可以配合内置函数zip,来同时遍历多个序列。关于zip的用法如下:
zip函数可以将任意多的序列类型数据结合起来,生成新序列数据。生成的新序列数据中,每个元素都是一个元组。该元组的元素是由传入zip函数中的多个序列数据的元素组成。例如:
x=[1,2,3] #定义2个列表,x与y
y=[3,2,"hello"]
t= zip(x,y) #通过zip生成一个新的序列t,这时t是zip类型
print(tuple(t)) #将t转成元组,并打印。输出:((1, 3), (2, 2), (3, 'hello'))
当然生成的序列t也可以转成列表(list)类型。例如:
x=[1,2,3] #定义2个列表,x与y
y=[3,2,"hello"]
t= zip(x,y) #通过zip生成一个新的序列t,这时t是zip类型
print(list(t)) #将t转成列表,并打印。输出:[(1, 3), (2, 2), (3, 'hello')]
需要注意的是,当zip对象(t)被转化为元组或列表后,就会自动销毁。如果再使用t,会得不到具体的元素。例如:
x=[1,2,3] #定义2个列表,x与y
y=[3,2,"hello"]
t= zip(x,y) #通过zip生成一个新的序列t,这时t是zip类型
print(list(t)) #将t转成列表,并打印。输出:[(1, 3), (2, 2), (3, 'hello')]
print(tuple(t)) #再次使用t,将t转成元组,得到的是空元组。输出: ()
zip对象还可以通过前面加个字符“*”的方式来完成unzip的过程,所谓unzip,就是将zip生成的数据返回去。例如:
x=[1,2,3] #定义2个列表,x与y
y=[3,2,"hello"]
t= zip(x,y) #通过zip生成一个新的序列t,这时t是zip类型
print(*t) #在t前面加个*,完成unzip。输出:(1, 3) (2, 2) (3, 'hello')
print(*t) #同样,t只能unzip一次,再次使用的时候,会返回空。没任何输出
上例中,在最后两行特意调用了两次zip对象t。可以看到第二次调用t时,得到的输出是空的。这也是值得注意的地方。
如果zip里面的序列长度不同,就会以最短的序列数据为主。例如:
x=[1,2,3,4,5,6] #定义2个list,x与y,x的长度会更大一些
y=[3,2,"hello"]
t= zip(x,y) #通过zip生成一个新的序列t,这时t是zip类型
print(list(t)) #将t转成列表,以最短的为主。输出:[(1, 3), (2, 2), (3,'hello')]
上例中,y的长度最短,只包含3个元素。所以生成的t也只有3个元素。
传入zip中的类型可以不同,下面演示下zip参数一个是列表一个是元组的情况:
x=[1,2,3,4,5,6] #定义1个列表x
y=(3,2,"hello") #定义1个元组y
t= zip(x,y) #通过zip生成一个新的序列t,这时t是zip类型
print(list(t)) #将t转成列表。输出:[(1, 3), (2, 2), (3, 'hello')]
上例中将列表x和元组y一起传入zip里,一样可以得出zip对象。表明zip的参数可以是任意序列类型。
了解完zip后,再来看一个zip与for组合的例子:
x=[1,2,3,4,5,6] #定义1个列表x
y=(3,2,"hello") #定义1个元组y
fort1,t2 in zip(x,y): #循环遍历zip后的z和y
print(t1,t2) #将t1,t2打印出来
for循环中,直接可以从zip对象取出每个迭代的元素,不需要在转成列表或元组。上例执行后,输出:
13
22
3hello
在for循环中,还可以使用内置函数enumerate来遍历一个序列容器。enumerate函数的作用是,可以将序列类型的数据生成带序号的新序列数据。具体用法如下:
使用enumerate生成的新序列中,每个元素都是一个元组,该元组是由传入enumerate函数中序列的元素与其对应的索引组成的。例如:
x=["hello",5,6] #定义1个列表x
t= enumerate (x) #通过enumerate生成一个新的序列t,这时t是enumerate类型
print(tuple(t)) #将t转成元组,并打印.输出:((0, 'hello'), (1, 5), (2, 6))
了解完zip后,再来看一个enumerate与for组合的例子:
x=["hello",5,6] #定义1个列表x
fori,t2 in enumerate (x): #循环遍历enumerate后的x
print(i,t2) #将i,t2打印出来
for循环中,需要定义2个变量来接收enumerate后的返回值。一个是元素的索引,一个是具体的元素。上例执行后,输出:
0hello
15
26
enumerate与for的结合为程序提供了更大的方便性。enumerate的第一个返回值在循环里同时也起到计数的作用,直接可以当作循环的次数来使用。
在循环内部可以使用break、continue和pass语句,来根据执行语句的具体情况,对循环的过程进行控制。具体意义如下:
l break:跳出当前的for或while循环;
l continue:终止当前这一次执行,进行循环的下一次迭代;
l pass:该语句什么都不做,是为了保持程序结构的完整性。常用在语法上需要一条语句,又不需要任何操作的情况下。
下面通过例子来演示这几个语句的使用。
下面模拟一个人机对话的场景,通过前面的控制流知识来对程序控制,实现完整的流程演示。
实例描述
通过一个循环来获得用户的输入,并根据不同的输入做不同的处理:
(1)如果输入“hello”,进入主程序,开启人机对话服务。
(2)如果输入“go away”或是“Bye”,退出程序。
(3)如果输入“pardon”,从新等待用户输入
建立一个while循环,在循环体内获取用户输入,并根据输入的内容,进行不同的操作(具体见代码中的注释),代码如下:
代码5-1:人机对话控制流程
getstr = '' #定义一个空字符串,用来接收输入
while("Bye"!=getstr): #使用while循环
if''==getstr: #如果输入字符为空,输出欢迎语句
print("hello! Password!")
getstr =input("请输入字符,并按回车键结束:")#调用input函数,获得输入字符串
if'hello'==getstr.strip(): #如果输入字符串为hello,启动对话服务
print('How are you today?')
getstr = "start" #将getstr设为start,标志是启动对话服务
elif 'goaway'==getstr.strip(): #如果输入的是go away,则退出
print('sorry! bye-bye')
break #使用break语句退出循环
elif'pardon'==getstr.strip(): #如果是pardon 重新再输出一次
getstr = ''
continue #continue将结束本次执行,开始循环的下一次执行
else:
pass #什么也不做,保持程序完整性
if'start'== getstr: #如果getstr为start,启动对话服务
print('…init dialog-serving…') #伪代码,打印一些语句,代表启动了对话服务
print('… one thing…')
print('… two thing…')
print('……')
这里只是模拟人机对话的控制流程,并没有实现人机对话的真实操作。人机对话部分使用了函数input来实现输入功能,回答部分使用了print函数输出字符串的方式来实现机器的输出功能。
代码运行后会显示如下输出:
hello!Password!
请输入字符,并按回车键结束:
程序停在这里,等待输入。这时输入“pardon”,会有如下输出:
请输入字符,并按回车键结束:pardon
hello!Password!
请输入字符,并按回车键结束:
可以看到代码中的if语句、elif语句、continue和while循环起到作用了。
(1) 程序先通过if语句判断输入是否是“hello”;
(2) 若不是,则进行elif语句接着判断;
(3) 一直执行到输入字符串与“pardon”相等的elif语句,执行该条件下的continue语句;
(4) 通过continue语句结束本次循环,开始重新迭代。
再次输入“hello”,会有如下输出:
请输入字符,并按回车键结束:hello
Howare you today?
…init dialog-serving…
… one thing…
… two thing…
……
请输入字符,并按回车键结束:
程序接收到“hello”指令,在内部将getstr设成了“start”。后面的代码会判断getstr的值,当getstr为“start”时,便开始启动人机对话服务。
接着输入“go away”或“Bye”程序退出。显示如下:
请输入字符,并按回车键结束:go away
sorry!bye-bye
列表推导式是一种创建列表的方法。它的应用场景为:当需要对一个序列数据中的每个元素做一些操作,并将操作后的结果作为新列表的元素时,就可以使用列表推导式。列表推导式提供了从序列创建列表的简单途径。它可以根据指定的条件来创建子序列。
写列表推导式时常常会与for结合在一起。一般会写成:在一个中括号里面写一个表达式,后面再跟一个或多个 for 或if子句。这样生成的列表中的元素就是一个for或if子句中遍历的具体元素,经过表达式生成的结果。例如:
Y=[1,0,1,0,1,1,1,1,0] #定义一个list,包含0,1两个元素
colors= ['r' if l == 0 else 'b' for l in Y[:]] #使用列表推导式将Y中的0变成“r”,1变成“b”
print(colors) #将colors内容打印出来,输出:['b', 'r', 'b', 'r', 'b','b', 'b', 'b', 'r']。
上面的代码常常用于绘图中某个点的颜色设置。假设列表Y是通过某种运算生成的结果,里面包含了两种结果(0和1)。现在要把Y中的0数据用红色(r)表示,1的数据用蓝色(b)表示。这时就可以使用列表推导式生成一个与Y对应的颜色列表。
列表推导式还可以生成嵌套列表或元组,例如:
m= [[1,2,3], [4,5,6], [7,8,9]] #定义一个列表
t= [ (r[0],r[1],r[2]) for r in m ] #外面的for是变量m的每一行,里面是将每行的三个元素变成元组
print(t) #m由嵌套列表变成了嵌套元组,输出:[(1, 2, 3), (4, 5, 6), (7, 8, 9)]
上面的第二行也可以写成t = [tuple(r) for r in m ],是一样的效果。
for 语句的循环次数是根据遍历序列容器中的数据个数来决定的。在遍历的过程中隐式地调用了内置函数iter。函数iter被调用后,会返回一个迭代器对象。迭代器对象定义了__next__ 方法,在每次访问时会得到一个元素。当没有任何元素时,__next__将通过StopIteration 异常来告诉 for 语句停止迭代。具体代码演示如下:
x=[1,2,3] #定义一个列表
it=iter(x) #调用iter函数返回一个迭代器对象
print(it.__next__()) #调用迭代器的__next__方法,返回一个元素。输出:1
print(it.__next__()) #调用迭代器的__next__方法,返回一个元素。输出:2
print(it.__next__()) #调用迭代器的__next__方法,返回一个元素。输出:3
print(it.__next__()) #再次调用迭代器的__next__方法,此时已经没有元素,返回StopIteration
上例中最后一句代码执行时,指针已经走到了列表的最后一个位置。再次获取元素时,发生了异常。在for语句中内置的代码会捕获到该异常,然后退出循环。
另外,Python中内置函数next函数,是迭代器对象中的__next__ 方法的另一种写法。所以上面的代码还可以写成如下样子:
x=[1,2,3] #定义一个列表
it=iter(x) #调用iter函数返回一个迭代器对象
print(next(it)) #调用迭代器的__next__方法,返回一个元素。输出:1
print(next(it)) #调用迭代器的__next__方法,返回一个元素。输出:2
print(next(it)) #调用迭代器的__next__方法,返回一个元素。输出:3
print(next(it)) #再次调用迭代器的__next__方法,此时已经没有元素,返回StopIteration
用迭代器访问对象是Python非常常用的现象。不仅是只有for循环,还有许多内置函数例如sum、min、max等函数内部实现的原理都是使用了迭代器访问对象。
内容来源于《python带我起飞——入门、进阶、商业实战》一书。
购买链接:http://t.cn/RBNS8fD
配套免费视频:http://v.qq.com/vplus/1ea7e3c40fd64cd5a25e9827b38c171e/foldervideos/xvp0024019vk2to