6.5 条件语句
到目前为止,我们编写的程序都是简单地按语句顺序一条一条执行的。本节将介绍让程序选择执行语句的方法。
6.5.1 布尔变量的作用
布尔变量我们在第2章已经有所接触,第2章的运算符中多处提到的True、False就是布尔变量,布尔变量一般对应的是布尔值(也称作真值,布尔值这个名字是根据对真值做过大量研究的George Boole命名的)。
下面的值在作为布尔表达式时,会被解释器看作假(False):
False None 0 "" () [] {}
换句话说,标准值False和None、所有类型的数字0(包括浮点型、长整型和其他类型)、空序列(如空字符串、空元组和空列表)以及空字典都为假。其他值都为真,包括原生的布尔值True。
Python中所有值都能被解释为真值,这可能会让你不太明白,但理解这点非常有用。在Python中,标准的真值有True和False两个。在其他语言中,标准的真值为0(表示假)和1(表示真)。事实上,True和False只不过是1和0的另一种表现形式,作用相同,例如:
>>> True True >>> False False >>> True == 1 True >>> False == 0 True >>> True+False+2 3
由上面的输出结果看到,在Python中,True和1等价,False和0等价。
布尔值True和False属于布尔类型,bool函数可以用来转换其他值,例如:
>>> bool('good good study') True >>> bool('') False >>> bool(3) True >>> bool(0) False >>> bool([1]) True >>> bool([]) False >>> bool() False
由输出结果看到,可以用bool函数做boolean值转换。
因为所有值都可以用作布尔值(真值),所以几乎不需要对它们进行显式转换,Python会自动转换这些值。
提 示
尽管[]和""都为假,即bool([])==bool("")==False,不过它们本身不相等,即[]!=""。其他不同类型的假值也是如此,如()!=False。
6.5.2 if语句
真值可以联合使用,首先看如下代码:
#! /usr/bin/python3 # -*- coding:UTF-8 -*- # if 基本用法
greeting='hello' if greeting == 'hello': print('hello')
该示例执行结果如下:
hello
该示例为if条件执行语句的一个实现示例。如果条件(在if和冒号之间的表达式)判定为真,后面的语句块(本例中是print语句)就会被执行;如果条件判定为假,语句块就不会被执行。
上述示例代码的执行过程如图6-5所示。
图6-5中的小黑点为if语句的起点,往后执行到条件语句(条件语句如greeting=='hello'),如果条件为真,就执行条件代码,然后结束这个if条件语句;如果条件为假,就跳过这段条件代码,这个if条件语句直接结束。
图6-5 if条件语句执行过程
在if语句块中还可以执行一些复杂操作,例如(文件名为if_use.py):
#! /usr/bin/python3 # -*- coding:UTF-8 -*-
# if 基本用法 greeting='hello' if greeting == 'hello': student={'小萌': '1001', '小智': '1002', '小强': '1005','小张': '1006'} print(f'字典元素个数为:{len(student)}') student.clear() print(f'字典删除后元素个数为:{len(student)}')
以上程序执行结果为:
字典元素个数为:4个 字典删除后元素个数为:0个
此处的if语句块由多条语句组成,编写过程中要注意保持语句的缩进一致,否则在执行时会报错。
if语句的条件判定除了使用==外,还可以使用>(大于)、<(小于)、>=(大于等于)、<=(小于等于)等条件符表示大小关系。除此之外,还可以使用各个函数或方法返回值作为条件判定。使用条件符的操作和使用==一样,使用函数或表达式的操作在后续章节会逐步介绍。
提 示
在练习过程中,要习惯编写示例中开头两行的写法,即习惯写以下两行代码:
#! /usr/bin/python3 # -*- coding:UTF-8 -*-
习惯写这两行代码可以帮助你在代码移植和编码问题上避免很多问题。代码移植时,如果从Windows移植到Linux系统上,就必须加上第一行代码。代码中有中文时,如果不加第二行代码,就很容易出现乱码的情况。
6.5.3 else子句
在if语句的示例中,当greeting的值为hello时,if后面的条件执行结果为true,进入下面的语句块中执行相关语句。如果greeting的值不是hello,就不能进入语句块,如果想显示相关提示,比如告诉我们greeting的值不为hello或执行的不是if中的语句块,该怎么办呢?例如(文件命名if_else_use.py):
#! /usr/bin/python3 # -*- coding:UTF-8 -*-
greeting='hi' if greeting == 'hello': print('hello') else: print('该语句块不在if中,greeting的值不是hello')
这段程序加入了一个新条件子句——else子句。之所以叫子句,是因为else不是独立语句,只能作为if语句的一部分。使用else子句可以增加一种选择。
该程序的输出结果如下:
该语句块不在if中,greeting的值不是hello
由输出结果看到,if语句块没有被执行,执行的是else子句中的语句块。同if语句一样,else子句中的语句块也可以编写复杂语句。
提 示
在else子句后面没有条件判定。
6.5.4 elif子句
在else子句的示例中,如果除if条件外,还有多个子条件需要判定,该怎么办呢?
Python为我们提供了一个elif语句,elif是else if的简写,意思为具有条件的else子句,例如(文件命名if_elif_use.py):
#! /usr/bin/python3 # -*- coding:UTF-8 -*-
num = 10 if num > 10: print('num的值大于10') elif 0<=num<=10: print('num的值介于0和10之间') else: print('num的值小于0')
由以上程序可知,elif需要和if、else子句联合使用,不能独立使用,并且必须以if语句开头,可以选择是否以else子句结尾。
程序输出结果如下:
num的值介于0和10之间
由输出结果得知,这段程序执行的是elif子句中的语句块,即elif子句的条件判定结果为true,所以执行这个子句后的语句块。
6.5.5 嵌套代码块
我们前面讲述了if语句、else子句和elif子句,这几个语句可以进行条件的选择判定,不过我们在实际项目开发中经常需要一些更复杂的操作,例如(文件命名if_nesting_use.py):
#! /usr/bin/python3 # -*- coding:UTF-8 -*-
num = 10 if num%2==0: if num%3==0: print ("你输入的数字可以整除 2 和 3") elif num%4==0: print ("你输入的数字可以整除 2 和 4") else: print ("你输入的数字可以整除 2,但不能整除 3 和 4") else: if num%3==0: print ("你输入的数字可以整除 3,但不能整除 2") else: print ("你输入的数字不能整除 2 和 3")
由上面的程序可知,在if语句的语句块中还存在if语句、语句块以及else子句,else子句的语句块中也存在if语句和else子句。
上面的程序输出结果如下:
你输入的数字可以整除 2,但不能整除 3 和 4
由输出结果可以看出,执行的是if语句块中else子句的语句块。
在Python中,该示例使用的这种结构的代码称作嵌套代码。所谓嵌套代码,是指把if、else、elif等条件语句再放入if、else、elif条件语句块中,作为深层次的条件判定语句。
6.5.6 更多操作
我们在第2章简单介绍过一些运算符,本节将对其中一些涉及条件运算的运算符做进一步讲解。
1. is:同一性运算符
is运算符比较有趣。我们先看如下程序:
>>> x=y=[1,2,3] >>> z=[1,2,3] >>> x==y True >>> x==z True >>> x is y True >>> x is z False
在最后一个输出语句之前,一切看起来非常美好,都在意料中,不过最后一个语句却出现了问题,为什么x和z相等却不相同呢?
这是因为is运算符用于判定同一性而不是相等性。变量x和y被绑定在同一个列表上,而变量z被绑定在另一个具有相同数值和顺序的列表上。它们的值可能相等,却不是同一个对象。
也可以从内存的角度思考,即它们所指向的内存空间不一样,x和y指向同一块内存空间,z指向另一块内存空间。
是不是看起来有些不可理喻,再看如下示例:
>>> x=[1,2,3] >>> y=[1,5] >>> x is not y True >>> del x[2] >>> x [1, 2] >>> y[1]=2 >>> y [1, 2] >>> x==y True >>> x is y False
在上面的程序中,列表x和y一开始是不同的列表,后面将列表值更改为相等,但还是两个不同的列表,即两个列表值相等却不等同。
综上所述,使用==运算符判定两个对象是否相等,使用is判定两个对象是否等同(是否为同一对象)。
提 示
尽量避免用is运算符比较数值和字符串这类不可变值。由于Python内部操作这些对象方式的原因,使用is运算符的结果是不可预测的,除非你对堆栈有一定熟悉程度,否则很难预测运算结果。
2. 比较字符串和序列
字符串可以按照字母排列顺序进行比较,我们在前面的章节已经介绍过。这里介绍其他序列的比较操作。
其他序列比较的不是字符而是元素的其他类型,例如:
>>> [1,2]<[2,1] True >>> [1,2]<[1,2] False >>> [1,2]==[1,2] True
由操作结果可知,也可以对列表进行比较操作。
如果一个序列中包括其他序列元素,比较规则也适用于序列元素,例如:
>>> [2,[1,2]]<[2,[1,3]] True
由操作结果看到,也可以对嵌套列表进行比较操作。
3. 布尔运算符
前面我们已经讲述过不少布尔运算的操作。不过有时要检查一个以上的条件,如果按照前面的操作方式,就会多走一些弯路,例如(文件命名boolean_oper.py):
#! /usr/bin/python3 # -*- coding:UTF-8 -*-
num = 10 if num <= 10: if num>=5: print('num的值介于5和10之间') else: print('num的值不介于5和10之间') else: print('num的值不介于5和10之间')
上面的程序在写法上没什么问题,但是走了一些不必要的弯路,可以将代码编写得更简洁:
if num <= 10 and num>=5: print('num的值介于5和10之间') else: print('num的值不介于5和10之间')
或者:
if 5 <= num <= 10: print('num的值介于5和10之间') else: print('num的值不介于5和10之间')
上面的程序明显更加简洁、易读。
and运算符用于连接两个布尔值,并在两者都为真时返回真,否则返回假。与and同类的还有or和not两个运算符。
布尔运算符有一个有趣的特性:只有在需要求值时才求值。举例来说,表达式x and y需要两个变量都为真时才为真,所以如果x为假,表达式就立刻返回false,无论y的值是多少。实际上,如果x为假,表达式就会返回x的值,否则返回y的值。这种行为被称为短路逻辑(short-circuit logic)或惰性求值(lazy evaluation)。布尔运算符通常被称为逻辑运算符,这种行为同样适用于or。在表达式x or y中,x为真时直接返回x的值,否则返回y的值。注意,这意味着在布尔运算符后面的代码都不会被执行。
6.5.7 断言
在Python中,有一个和if语句工作方式非常相近的关键字,其工作方式类似如下伪代码:
if not condition: crash program
在Python中为什么需要这样的代码呢?
在没完善一个程序之前,我们不知道程序会在哪里出错,与其在运行时崩溃,不如在出现错误条件时就崩溃。一般来说,可以要求一些条件必须为真。在Python中,assert关键字就能实现这种工作方式。先来看一个示例:
>>> x=3 >>> assert x > 0, "x is not zero or negative" >>> assert x%2 == 0, "x is not an even number" #提示x不是偶数 Traceback (most recent call last): File "<stdin>", line 1, in <module> AssertionError: x is not an even number
由上面的输出结果看到,当assert后面的条件为真时,程序正常运行;当assert后面的条件为假时,输出错误信息。错误的提示信息由我们自己定义,这个错误提示信息可以称为异常参数。assert的异常参数是在断言表达式后添加的字符串信息,用来解释断言并更容易知道问题出在哪里。
使用assert断言是学习Python的好习惯,Python assert断言语句的格式及用法很简单。
使用assert断言时,要注意以下几点:
(1)assert断言用来声明某个条件是真的。
(2)如果你非常确信使用的列表中至少有一个元素,想要检验这一点,并在它非真时引发一个错误,那么assert语句是应用在这种情形下的理想语句。
(3)assert语句失败时,会引发一个AssertionError。