Python基础--第5章 控制流——控制执行顺序的开关

控制流又叫做流程控制,就是根据具体情况来控制程序,执行某些特定的程序块。Python的流程控制语句包括if条件语句、while循环语句和for循环语句。其中还细分为range函数、break、continue、pass等内部流程的控制语句。下面就来详细说说它们的用法。

5.1  if语句

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<b]。这是一个小技巧,可以使代码更为简洁。

这种由两个中括号组成的语法,完整的意思为:

如果第二个中括号里的条件值为假,则返回第一个中括号中的第一个元素;如果第二个中括号里的条件值为真,则返回第一个中括号中的第二个元素。

 

5.2  while语句

While是用来表述一个循环执行的代码流程,语句的形式为:

while条件一: 

    statements1 

该语句的意思如下:

(1)   先执行条件一判断语句,看是否返回为True;

(2)   如果返回True,则执行下面的statements1代码;

(3)   执行完statements1的代码后,在回到(1),

(4)   如果(1)返回False,则整个语句结束。

statements1属于while的子代码块,每一行的开头都需要缩进。

 

5.3  for语句

Python中的for语句与while语句都是用来表述一个循环执行的代码流程。for的循环条件不是一个判断语句,而是一个序列容器的遍历。表述形式为:

foritem in 序列数据:

        statements1

意思是,每次从序列容器中取一个值(item),然后执行语句statements1。当遍历完整个序列容器,整个循环也就结束了。

5.3.1  在for循环中切片的使用

序列容器可以是任何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中的数据遍历完。注意,一定要避免这种错误的写法。

5.3.2  在for循环中内置函数range的使用

在for循环中,还可以使用内置函数range来遍历一个数字序列。关于range的用法如下:

1. 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]

2. range与for结合

了解完range后,再来看一个range与for组合的例子:

fori in range(5):     #循环遍历0到5之间的整数

    print(i)            #将取出的值打印出来

这样就实现了循环5次的控制。用range中放置个整数(5)的方式,可以实现指定代码的具体循环次数。上例执行后,输出:

0

1

2

3

4

5.3.3  在for循环中内置函数zip的使用

for语句还可以配合内置函数zip,来同时遍历多个序列。关于zip的用法如下:

1. 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的参数可以是任意序列类型。

2. zip与for结合

了解完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

5.3.4  在for循环中内置函数enumerate的使用

在for循环中,还可以使用内置函数enumerate来遍历一个序列容器。enumerate函数的作用是,可以将序列类型的数据生成带序号的新序列数据。具体用法如下:

1. 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))

2. enumerate与for结合

了解完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的第一个返回值在循环里同时也起到计数的作用,直接可以当作循环的次数来使用。

5.4  break、continue、pass 

在循环内部可以使用break、continue和pass语句,来根据执行语句的具体情况,对循环的过程进行控制。具体意义如下:

l break:跳出当前的for或while循环;

l continue:终止当前这一次执行,进行循环的下一次迭代;

l pass:该语句什么都不做,是为了保持程序结构的完整性。常用在语法上需要一条语句,又不需要任何操作的情况下。

下面通过例子来演示这几个语句的使用。

5.5  实例:演示人机对话中的控制流程

下面模拟一个人机对话的场景,通过前面的控制流知识来对程序控制,实现完整的流程演示。

实例描述

通过一个循环来获得用户的输入,并根据不同的输入做不同的处理:

(1)如果输入“hello”,进入主程序,开启人机对话服务。

(2)如果输入“go away”或是“Bye”,退出程序。

(3)如果输入“pardon”,从新等待用户输入

1. 编写代码

建立一个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函数输出字符串的方式来实现机器的输出功能。

2. 运行程序

代码运行后会显示如下输出:

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

 

5.6  利用for循环实现列表推导式

列表推导式是一种创建列表的方法。它的应用场景为:当需要对一个序列数据中的每个元素做一些操作,并将操作后的结果作为新列表的元素时,就可以使用列表推导式。列表推导式提供了从序列创建列表的简单途径。它可以根据指定的条件来创建子序列。

写列表推导式时常常会与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 ],是一样的效果。

5.7  for的原理——迭代器

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


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值