1.2 三大结构

Python语言中有三大结构:循序、分支和循环。这三种结构分别适用于不同的情况,一个复杂的程序中常常同时包含这三种结构。

1.2.1 循序结构

说到“循序”这个词,我们第一个联想到的成语就是“循序渐进”。循序结构和它的名字一样,是按程序内语句的排列顺序运行程序的意思。在前面讲解变量时,我们所举的例子都是循序结构的。这也是Python中最简单的结构。

循序结构的运行过程如图1.7所示。

图1.7 循序结构

我们来看一段循序结构的程序吧。如果想让计算机输出我输入的数字的3倍,该怎么实现呢?先自己想想,再看下面的程序。

01 num=int(input("Enter a number: "))

02 result=num*3

03 print(result)

在这段程序中,第一行语句运行完之后,会进入第二行运行,然后再进入第三行。也就是说,排在前面的语句先运行。

1.2.2 分支结构

在Python中,分支结构只有一种:if语句及它的衍生语句。if语句是根据一条或多条语句的判定结果(True和False)来执行对应操作的语句,从而实现“分支”的效果。如上所述,if语句常常用于程序中的条件判断。

分支结构 if 语句的运行过程如图1.8所示。除了最基本的 if 语句,还有 if...else 语句和if...elif...else语句,它们可以实现更多的分支和更复杂的逻辑。

图1.8 if语句

在if语句中,如果条件语句的值为True,那么执行一段程序;如果值为False,那么不执行这段程序,跳过它直接进入下面的程序。

在if...else语句中,如果条件为True,执行第一段程序,如果为False,执行第二段程序,然后再进入if语句下面的程序,如图1.9所示。

图1.9 if...else语句

在 if...elif...else 语句中,如果第一个条件语句为True,则执行第一段程序然后直接进入 if后面的程序;如果第一个条件语句为False,则继续判断第二个条件语句。如果第二个条件语句为True,那么执行第二段程序;如果为False,则执行第三条语句,最后执行完毕,也进入 if后面的程序,如图1.10所示。

图1.10 if...elif...else语句

在了解分支结构if之后,还不能直接开始编写有关分支结构的程序。首先要探究条件语句的返回值,也就是它的判定结果:True和False。

1.2.3 条件判断

Python认定0或者null(空)为False,任意非0值或者任意非空值为True。这个判定结果也是一种变量—布尔型变量(boolean),它可以被定义或者返回。这种变量的值只有两种:True和False。换句话说,这种变量是用来存储对或错的变量。

我们来看一个例子。其中,bool函数可以把其他类型的变量转换为布尔型变量:

01 judge1=bool(1)

02 judge2=bool("String")

03 judge3=bool("")

04 judge4=bool(0)

05 print(judge1,judge2,judge3,judge4)

运行程序,输出结果为:

True True False False

接下来要了解的是如何在条件语句中检查是否相等,以及如何比较数字的大小。

在Python中,判断值是否相等使用“==”,也就是两个等号;判断值是否不相等使用“!=”,也就是一个感叹号和一个等号。

我们用程序来探究这两种语句的返回值:

01 num=5

02 string="Hello"

03 print(num==5)

04 print(num!=5)

05 print(num==4)

06 print(string!="Hello")

运行这段程序,输出结果为:

True

False

False

False

这段程序中的第一个条件语句num==5的返回值是True,因为num的值确实与5相等;其他的语句都是不成立的,所以返回False。不仅仅是数字,其他类型的变量也可以使用是否相等和是否不相等来判断。

现在来比较数字的大小。

先看程序,自己思考一下可能的比较方法,再去看讲解吧!

01 year=2018

02 print(year > 2000)

03 print(year >=2003)

04 print(year < 2018)

05 print(year <=2018)

运行程序,输出结果为:

True

True

False

True

显而易见,“>”“>=”“<”“<=”分别对应大于、大于等于、小于、小于等于,和我们熟悉的数学比较一样。如果式子成立,那么返回值为True;如果不成立,那么返回值为False。

还可以将多条语句连接起来,从而达到一次性检查多个条件的效果。

先来看一段程序:

01 name="Lucas"

02 judge=False

03 print(name.upper()=="LUCAS" and judge)

04 print(name.upper()=="LUCAS" or judge)

05 print(name=="abc" or True)

运行程序,输出结果为:

False

True

True

在上一节中讲过,upper函数的作用是把字符串内所有的英文字符都转换为大写形式。所以,name.upper()=="LUCAS"成立,返回的值是True。然而,由于and和or两种关键字的功能不一样,最终的结果也不一样。使用关键字and时,在a and b中,a和b两个值必须都是True,整条语句的值才能是True,只要有一个是False,那么整条语句就是False。而使用or时,在a or b中,只要有一个值是True,整条语句的值就是True,两个值都是False时才会返回False。所以,因为judge==False,所以第一条语句的输出是False,第二条语句的输出是True。相反,第三条语句的输出中尽管name和字符串"abc"并不相等,但因为or后面的第二个值是True,所以输出的值也是True。

在Python中,and和or可以叠加,并默认从左往右运算。就是说,a and b and c or d这条语句的默认运算顺序为(((a and b)and c)or d)。如果想要更改顺序,比如想先判断c or d,那么可以加上括号来提高优先级。比如(a and b)and(c or d)就是先判断a and b和c or d,再把这两个结果用and进行判断。

1.2.4 应用分支结构

在1.2.2节中我们简略地了解了三种分支结构的功能和用法。在本节中,我们将根据几个问题,对if、if...else、if...elif...else进行实际运用。

输入出生年份,根据年份判断这个人是否成年(假设今年为2018年):

01  year=int(input("Enter the year you born: "))

02  if 2018-year >=18:       #判断今年(2018)减去出生年份是否大于或等于18

03    print("You are an adult this year!")

我们注意到,if语句的末尾有冒号,而print语句并没有与if语句对齐—它的前面有缩进。

冒号标志着if判断的结束,而if下方有缩进的代码是在True的条件下要运行的,可以有很多行,一直到缩进再次改变时运行才结束。我们把这一段缩进相同的代码称作代码块。整个程序的缩进方式必须一致,我们通常使用 Tab(按一下)或者空格(按四下)进行缩进。Python 对于缩进和复合语句结尾的冒号要求极其严格,如果弄错会报错。缩进的不同会大大影响一个程序的运行效果。

在这段程序中,print语句缩进了,所以print是if内部的代码块。所以,如果2018-year>=18为True,那么计算机会执行print语句;反之,如果这条语句的结果是False,那么程序将会直接跳过if结构内的代码,然后结束程序。

我们来看第二个问题:输入一个整数,让计算机判断它是偶数还是奇数,然后输出结果。先想想,用已经学过的语法来写该怎么做呢?

这个问题用if语句也可以实现:

01  num=int(input("Enter a integer:"))

02  if num%2==0:       #如果num除以2余0

03    print("Even number")

04  if num%2==1:       #如果num除以2余1

05    print("Odd number")

运行程序,若输入的数字被2除的余数为0则输出是偶数;若输入的数字被2除的余数为1则输出是奇数。

上面这段程序中用到了两个if语句,但实际上一共只有两种情况,如果余数不为0就是1。为了使程序的运行速度更快,编写起来更方便,可以用if...else语句:

01  num=int(input("Enter a integer:"))

02  if num%2==0:        #如果num除以2余0

03    print("Even number")

04  else:             #if的判定结果不是True时执行else

05    print("Odd number")

这段程序和上一段程序的运行结果是一样的,但只需进行一次 if 判断,如果结果是 True就运行第一个代码块,如果是False就运行else里的第二个代码块。在同一个if...else语句中,关键词if和else应当有同样的缩进,而且都要以冒号结束。它们下面的代码块也应该有同样的缩进。

之前我们讲到了有两种分支时该如何编写程序,那么再来看本节最后一个问题:电影院规定,7岁以下儿童看电影免费,7岁到14岁的儿童半价,60岁及以上的老人也是半价,其他年龄的观众都是原价。如何才能输入一个人的年龄后判断他买票有什么优惠呢?(年龄小于0岁要输出错误提示。)

如果用学过的语法来做的话,要用到4个if语句。也就是说,就算在第一个if语句已经符合条件并打印出结果的情况下,也要继续进行剩余的判断。下面将要用到的if...elif...else语句就可以避免这种情况的发生并提高运行速度:

01  age=int(input("Enter your age:"))

02  if age < 0:

03    print("Error")

04  elif age >=0 and age<7:

05    print("Free")

06  elif(age >=7 and age < 14)or age >=60:

07    print("Half price")

08  else:

09    print("Full price")

elif就是else if的缩写,就是在else中再判断一个新的条件。elif可以无限叠加,直到你想要判断的条件全部判断完。从上往下运行,只要有一个条件符合(True),计算机就会执行这个if或elif里面的程序,随后跳出整条语句。

只有所有判断语句都不符(False)时,程序才会运行到最后的else那里。如果不用考虑全部不符合的情况,else是可省略的。

1.2.5 循环结构

循环结构是可以多次执行同一段代码的语句结构。在Python中有两种循环语句:while 语句和for语句。与Java和C不同,Python中没有do...while循环。

while 语句的结构如图1.11所示,在本次循环开始之前先对条件语句进行判断,如果条件语句的值为True则循环一次后再次进行判断。如果条件语句的值为False则循环结束。这里的条件语句和if中的条件语句是一样的。

图1.11 while循环

正是由于 while 语句的这种特性,我们常常在不确定循环次数的时候使用它,或者把它写成死循环。此外,还可以用else在while循环条件为False时(此时循环结束)运行另一段代码。

for语句的结构如图1.12所示,从图中看它和while语句的结构相似,但其实它们的功能有很多不同。在for循环的开始,我们要提供一个范围,无论是一个数的大小范围还是一个列表;循环开始时,会用一个变量存储本次循环的值,每循环一次就更新一次这个变量的值。

图1.12 for循环

当变量的值不在提供的范围内时,循环结束。for循环的这种特质,使得它成为我们要确定循环次数时的首选结构,它用于存储的变量也为我们编写程序提供了很多便利。

与分支结构相似,for循环也由关键字开头,用冒号结尾,内部的代码块也要有缩进。

1.2.6 continue和break

continue和break这两条语句经常出现在循环结构中,它们的作用是让程序跳出这一次循环或是整个循环。由于这种非正常退出循环通常要满足对应的条件,所以 continue 和 break 一般需要配合if语句使用。

看一下示例程序来了解如何使用continue语句:

01  arr=[1,2,3,4,5,6,7,8,9,10]

02  for i in range(len(10))

03    if arr[i]%5==0:

04     continue

05    print(arr[i])

运行程序,输出结果为:

1

2

3

4

6

7

8

9

我们发现,在列表中能被5整除的数都没有被输出。这证明循环运行到能被5整除的数时就停下并且退出这一次循环。

把continue换成break之后,再次运行整个程序:

01  arr=[1,2,3,4,5,6,7,8,9,10]

02  for i in range(len(10))

03    if arr[i]%5==0:

04       break

05    print(arr[i])

运行程序,输出结果为:

1

2

3

4

在列表中出现第一个能被5整除的数之后,break就跳出了整个循环,所以数组后面的几个数就不会被输出了。

1.2.7 应用循环结构

在简单认识了循环结构之后,本节将会把两种循环应用到实践中。

我们要做一个用于计算年龄的程序,让用户输入出生年份和今年的年份,相减得到他今年的年龄。但是,年龄不可能是负数,所以,如果出生年份大于今年的年份,要提醒用户输错了,并允许用户重新输入出生年份和今年的年份。

先自己想想该怎么做,再看正确答案:

运行程序,如果输入的出生年份一直大于今年,则计算机仍然执行 while 循环,会让用户一直重新输入,直到输入正确,随后执行else语句,然后结束。如果一开始的输入就正确,则不会执行while循环,直接进入else语句并输出结果。如果不想让while循环结束时再执行其他代码,可以删掉else语句。

接下来写一段计算一个数的阶乘的程序。数 n 的阶乘写作 n!,是这样计算的:n!=n×(n-1)×(n-2)×(n-3)×...3×2×1。让用户输入一个数(默认为正整数),然后输出它的阶乘,先自己想想这个问题用while循环该怎么实现,再看下面的例子:

在这段程序中,在while循环开始前先定义了两个变量:count和result。count用于计算次数,从1开始,每次循环都+1,记录本次循环为第几次。result用于存储计算结果,根据阶乘的计算方法,我们从1开始,一直连续乘到n,此时count=n,再加1后就大于n,此时跳出循环并输出结果。需要注意的是,代码中的“result*=count”和“count+=count”是“result=result*count”和“count=count+1”的简写。

在前面的内容中曾提到,在循环次数确定的情况下还可以使用 for 循环。下面的程序就是用for循环实现的,与上一段程序有同样的功能:

for循环的语法格式是“for 迭代变量 in 范围:”,和while循环一样有关键词、冒号和代码块的缩进。for循环默认迭代变量每次循环都+1,变量名称可以自己定义,常用的有i、j等,只在这个循环中有效(在循环外无法调用这个变量)。这条语句中的range是一个Python内置函数,用于定义一个列表,用作数据范围,在for循环中极其常用(当然也有for循环不需要用到range函数的情况,我们会在1.3节讲到)。它可以写为range(x),range(x,y)或 range(x,y,z)。range(x)的功能是定义一个从0到x-1的列表作为循环范围,range(x,y)是定义一个从x到y-1的列表,而range(x,y,z)则是在定义一个列表的同时,把默认的每次循环变量+1改成+z(z可以是负数)。

现在,你知道为什么第3行程序中定义的是range(1,n+1)而不是range(1,n)了吗?

前面还讲到,while循环可以用来编写死循环。直接来看程序:

这个程序永远不会自动结束,因为while后面的判断条件永远正确,所以程序会一直输出。

现在,再学习两条语句:continue 和 break。continue 的作用是“跳过这一次循环”,break的作用是“跳出整个循环”。

为了更加生动地展示它们的功能,我们尝试在上面的程序中加入这两条语句。

运行程序,输出结果为:

我们发现,程序并没有无限循环下去,而是在输出11后结束了;并且,5的倍数都没有被输出。这是因为,我们用if语句在for循环中设置了分支,如果count为5的倍数,则count+=1后continue,也就是回到while语句,直接进入下一次循环,不再执行代码块后面的程序。

而当count的值为12时,用break跳出这个循环,到达程序结尾,也没有执行程序块后面的程序。

1.2.8 结构的嵌套

在1.2.7节中,我们看到了循环结构while和分支结构if的嵌套。本节会讲解另外两个结构互相嵌套的例子。

写一个用于做整数除法的程序,让用户输入被除数和除数。由于除数不能为0,所以,如果输入的除数是0,输出错误提示并结束程序。而除法的结果可能是整数或小数,在输出结果的同时,也输出结果的类型。

先自己思考一下该怎么做,再来看下面的程序:

这一段程序中用到了两个if...else语句,其中一条语句在另一条语句的内部,也就是说,第一个if语句的代码块中包含了另一条if语句。这样的写法同样适用于其他结构。

我们再来看第二个例子。在一所学校内,学生都有自己单独的学号,它们由两个两位数组成。但是,这些学号有一个规律:假设学号为ab cd,其中两位数ab不超过20,两位数cd不超过30,同时两位数的开头不能是0。要把所有的学号都输出该怎么做?

同样,先自己思考,再看下面的程序:

01  for i in range(10,21):

02    for j in range(10,31):

03     print(i,j)

用两个for循环嵌套起来,程序很快就写完了。这意味着,第一个for循环每循环一次,都要把第二个for循环全部走完。这比起把所有学号都自己枚举出来然后一起输出要快得多。