第3章程序控制结构与函数设计
3.1选 择 结 构
生活中处处充满了选择: 如果周末不下雨我就约朋友去爬山,否则就去教学楼大厅里打太极拳;如果某个同学平时学习很认真但是期末考试前确实因为临时有事耽误了复习而没有考好,只要差得不太多我也一样给打及格;去市场买菜的时候比较一下,哪家的菜又好又便宜就买哪家的;诸如此类,我们时刻都在根据实际条件做出这样或那样的选择。编写程序也是如此,当某个条件得到满足时就去做特定的事情,否则就做另一件事情,这就是选择结构。
3.1.1条件表达式
在选择结构和循环结构中,都要根据条件表达式的值来确定下一步的执行流程。条件表达式的值只要不是False、0(或0.0、0j等)、空值None、空列表、空元组、空集合、空字典、空字符串、空range对象或其他空迭代对象,Python解释器均认为与True等价。从这个意义上来讲,所有的Python合法表达式都可以作为条件表达式,包括含有函数调用的表达式。例如: >>> if 3:#使用整数作为条件表达式
print(5)
5
>>> a=\[1, 2, 3\]
>>> if a:#使用列表作为条件表达式
print(a)
\[1, 2, 3\]
>>> a=\[\]
>>> if a:
print(a)
else:
print('empty')
empty
>>> i=s=0
>>> while i <= 10:#使用关系表达式作为条件表达式s += i
i += 1
>>> print(s)
55
>>> i=s=0
>>> while True:#使用常量True作为条件表达式
s += i
i += 1
if i>10:#符合特定条件时使用break语句退出循环
break
>>> print(s)
55
>>> s=0
>>> for i in range(0, 11, 1):#遍历序列元素
s += i
>>> print(s)
55[1]〖2〗Python可以这样学[1]第3章程序控制结构与函数设计〖2〗关于表达式和运算符的详细内容在1.3.3节中已有介绍,这里不再赘述,只重点介绍一下比较特殊的几个运算符。首先是关系运算符,与很多语言不同的是,在Python中的关系运算符可以连续使用,例如:>>> print(1<2<3)
True
>>> print(1<2>3)
False
>>> print(1<3>2)
True在Python中,条件表达式中不允许使用赋值运算符“=”,避免了其他语言中误将关系运算符“==”写作赋值运算符“=”带来的麻烦,例如,下面的代码在条件表达式中使用赋值运算符“=”将抛出异常,提示语法错误。>>> if a=3:#条件表达式中不允许使用赋值运算符
SyntaxError: invalid syntax
>>> if(a=3)and(b=4):
SyntaxError: invalid syntax比较特殊的运算符还有逻辑运算符and和or,这两个运算符具有短路求值或惰性求值的特点,简单地说,就是只计算必须计算的表达式的值。以and为例,对于表达式“表达式1 and 表达式2”而言,如果“表达式1”的值为False或其他等价值时,不论“表达式2”的值是什么,整个表达式的值都是False,此时“表达式2”的值无论是什么都不影响整个表达式的值,因此将不会被计算,从而减少不必要的计算和判断。另外,Python中的逻辑运算符在某些方面和其他语言也有所不同,例如: >>> 3 and 5
5
>>> 3 or 5
3
>>> 0 and 5
0
>>> 0 or 5
5
>>> not 3
False
>>> not 0
True下面的函数使用指定的分隔符把多个字符串连接成一个字符串,如果用户没有指定分隔符则使用逗号。>>> def Join(chList, sep=None):
return(sep or ',').join(chList)#注意:参数sep不是字符串时会抛出异常
>>> chTest=\['1', '2', '3', '4', '5'\]
>>> Join(chTest)
'1,2,3,4,5'
>>> Join(chTest, ':')
'1:2:3:4:5'
>>> Join(chTest, ' ')
'1 2 3 4 5'当然,也可以把上面的函数直接定义为下面带有默认值参数的形式: >>> def Join(chList, sep=','):
return sep.join(chList)小技巧: 在设计包含多个条件的条件表达式时,如果能够大概预测不同条件失败的概率,并将多个条件根据and和or运算符的短路求值特性来组织顺序,可以大幅度提高程序运行效率,减少不必要的计算,这也属于代码优化的内容。
拓展知识: 逻辑运算符与常见电路连接方式的相似之处。大家应该都学过高中物理,还记得并联电路、串联电路、短路这样的概念吗?可以做个简单类比,or运算符类似于并联电路,只要有一个开关是通的那么灯就是亮的;and运算符类似于串联电路,必须所有开关是通的那么灯才是亮的;not运算符类似于短路电路,如果开关通了那么灯就灭了,如图31所示。
图31逻辑运算符与几种电路的类比关系
3.1.2选择结构的几种形式
选择结构通过判断某些特定条件是否满足来决定下一步的执行流程,是非常重要的控制结构。常见的有单分支选择结构、双分支选择结构、多分支选择结构以及嵌套的分支结构,形式比较灵活多变,具体使用哪一种最终还是取决于要实现的业务逻辑。循环结构和异常处理结构中也可以带有else子句,也可以看作是特殊形式的选择结构。
1. 单分支选择结构
单分支选择结构是最简单的一种形式,其语法如下所示,其中表达式后面的冒号“:”是不可缺少的,表示一个语句块的开始,后面几种其他形式的选择结构和循环结构中的冒号也是必须要有的。图32单分支选择结构
if 表达式:
语句块当表达式值为True或其他等价值时,表示条件满足,语句块将被执行,否则该语句块将不被执行,继续执行后面的代码(如果有),如图32所示。
下面的代码简单演示了单分支选择结构的用法: x=input('Input two numbers:')
a, b=map(int, x.split())
if a>b:
a, b=b, a#序列解包,交换两个变量的值
print(a, b)注意: 在Python中,代码的缩进非常重要,缩进是体现代码逻辑关系的重要方式,同一个代码块必须保证相同的缩进量。有的老师让学生学习Python的原因之一就是Python对代码排版或布局的严格要求可以培养学生严谨的习惯。而实际上,只要遵循一定的约定,Python代码的排版是可以降低要求的,例如下面的代码: >>> if 3>2: print('ok')#如果语句较短,可以直接写在分支语句后面
ok
>>> if True:print(3);print(5)#在一行写多个语句,使用分号分隔
3
5小提示: 在上面代码中,“a, b=b, a”是Python序列解包的用法,用来交换两个变量的值,等价于C语言的如下3条代码(假设变量已经声明并且类型正确),关于序列解包更多内容请参考2.5节。c=a;
a=b;
b=c;2. 双分支选择结构
双分支选择结构的语法为if 表达式:
语句块1
else:
语句块2当表达式值为True或其他等价值时,执行语句块1,否则执行语句块2,如图33所示。
图33双分支选择结构
下面的代码演示了双分支选择结构的用法: >>> chTest=\['1', '2', '3', '4', '5'\]
>>> if chTest:
print(chTest)
else:
print('Empty')
\['1', '2', '3', '4', '5'\]拓展知识: Python还提供了一个三元运算符,可以实现与选择结构相似的效果。语法为value1 if condition else value2当条件表达式condition的值与True等价时,表达式的值为value1,否则表达式的值为value2。另外,value1和value2本身也可以是复杂表达式,也可以包含函数调用。下面的代码演示了上面的表达式的用法,可以看出,这个结构的表达式也具有惰性求值的特点。>>> a=5
>>> print(6)if a>3 else print(5)
6
>>> print(6 if a>3 else 5)#注意,虽然结果与上一行代码一样,但代码含义不同
6
>>> b=6 if a>13 else 9#赋值运算符优先级低
>>> b
9
>>> x=math.sqrt(9)if 5>3 else random.randint(1, 100)
#此时还没有导入math模块
Traceback(most recent call last):
File "", line 1, in
x=math.sqrt(9)if 5>3 else random.randint(1,100)
NameError: name 'math' is not defined
>>> import math
#此时没有导入random模块,由于条件表达式5>3的值为True,所以可以正常运行
>>> x=math.sqrt(9)if 5>3 else random.randint(1,100)
#第一个条件表达式2>3的值为False,需要计算第二个表达式的值,然而此时还没有导入random模块,从而出错
>>> x=math.sqrt(9)if 2>3 else random.randint(1, 100)
Traceback(most recent call last):
File "", line 1, in
x=math.sqrt(9)if 2>3 else random.randint(1,100)
NameError: name 'random' is not defined
>>> import random
>>> x=math.sqrt(9)if 2>3 else random.randint(1, 100)最后,三元运算符是可以嵌套使用的,可以实现多分支选择的效果,但这样的代码可读性非常不好,不建议使用。>>> x=3
>>>(1 if x>2 else 0)if f(x)>5 else('a' if x<5 else 'b')
#可以嵌套使用,但不提倡这样用
1
>>> x=0
>>>(1 if x>2 else 0)if f(x)>5 else('a' if x<5 else 'b')
'a' 3. 多分支选择结构
多分支选择结构为用户提供了更多的选择,可以实现复杂的业务逻辑,多分支选择结构的语法为if 表达式1:
语句块1
elif 表达式2:
语句块2
elif 表达式3:
语句块3
else:
语句块n其中,关键字elif是else if的缩写。下面的代码演示了如何利用多分支选择结构将成绩从百分制变换到等级制。>>> def func(score):
if score>100:
return 'wrong score.must <= 100.'
elif score >= 90:
return 'A'
elif score >= 80:
return 'B'
elif score >= 70:
return 'C'
elif score >= 60:
return 'D'
elif score >= 0:
return 'E'
else:
return 'wrong score.must >0'
>>> func(120)
'wrong score.must <= 100.'
>>> func(99)
'A'
>>> func(87)
'B'
>>> func(62)
'D'
>>> func(3)
'E'
>>> func(-10)
'wrong score.must >0'4. 选择结构的嵌套
选择结构可以进行嵌套来表达复杂的业务逻辑,语法如下: if 表达式1:
语句块1
if 表达式2:
语句块2
else:
语句块3
else:
if 表达式4:
语句块4图34代码层次与隶属关系
……