
2.3 判断与循环
判断和循环是程序逻辑的重要组成部分。通过判断和循环,我们可以实现很多复杂的功能。
2.3.1 判断
判断语句(If-Statement)通常基于某种条件触发,当条件满足时,执行一些特定的操作。
1. if语句
Python使用关键字if语句实现判断,最简单的用法为:

它包含这样几个部分:
● if关键字,表示这是一条判断语句;
● <condition>表示判断的条件,当这个条件被满足(即条件为真)时,执行<statements>中的代码,条件不满足,<statements>中的代码不会被执行;
● 冒号表示判断代码块的开始;
● <statements>表示条件满足时,执行的代码块。
例如,对于下面的代码:

x满足大于0的条件,所以程序会打印出相关文字。条件不满足时,程序不会执行if代码块中的部分:

当判断语句执行的代码块结束时,之后的代码需要回到判断语句开始时的缩进状态才能继续执行:

x<0的情况:

在这两个例子中,最后一句并不是if语句中的内容,所以不管条件满不满足,它都会被执行。
2. elif和else语句
一个完整的if结构通常如下所示:

关键字elif是else if的缩写。其执行过程为:
● 条件<condition 1>满足,执行if后的代码块,跳过elif和else的部分;
● 条件<condition 1>不满足,跳过if后的代码块,转到第一个elif语句看条件<condition 2>,<condition 2>满足时执行它对应的代码块,否则转到下一个elif;
● 如果if和elif的条件都不满足,执行else对应的代码块。例如:

对于一个if语句,elif的个数没有限制,可以没有,可以有1个,也可以有多个。
例如,不使用elif:

使用多个elif:

else语句最多只有一个,也可以没有,如果出现,要放在所有的if和elif语句后面。
3. 判断条件
我们可以在判断语句中可以使用布尔型变量作为判断条件。事实上,Python对于判断条件没有任何限制,除了布尔型,判断条件可以是数字、字符串,也可以是列表、元组字典等结构。
在Python中,大部分的值都会被当作真,除了以下几种情况:
● False,包括所有计算结果为False的表达式;
● None,包括所有计算结果为None的表达式;
● 整数0值,包括所有计算结果为0的表达式;
● 空字符串,空列表,空字典,空集合,空元组。
浮点数0.0值也会被当作False:

但是不推荐使用浮点数作为判断条件,因为浮点数存在精度的问题:

虽然计算的结果是0.0,但是if条件却执行了。
复杂的判断条件可以使用关键字and、or和not进行组合得到,它们分别对应且、或、非的操作:

组合的对象可以不是布尔型:

对于关键字and:
● 如果两个值都为真,返回第二个值;
● 如果至少有一个值为假,返回第一个为假的值。
and的返回值是传入的表达式值,而不是True或者False,如:
In [25]: [] and 2333
Out[25]: []
与and相反,对于关键字or来说:
● 如果两个值都为假,返回第二个值;
● 如果至少有一个值为真,返回第一个为真的值。
如:
In [26]: [] or 0
Out[26]: 0
4. 判断的简单实例
我们用判断语句来判断一个年份是不是闰年。
闰年(Leap Year)的定义是这样的:普通年能被4整除且不能被100整除的为闰年,如2016是闰年,2017不是闰年;逢百的世纪年能被400整除的为闰年,如1900年不是闰年,2000年是闰年。
按照上面的逻辑,若年份变量为year,则第一个判断逻辑为:
year % 4 == 0 and year % 100 != 0
第二个判断逻辑为:
year % 400 == 0
为此,我们的程序可以写成:

或者使用关键字or将两个条件合并:

关键字and、or、not是有运算先后关系的:先算not,再算and,最后算or。为了避免混淆,我们将第一个and的内容用括号放在了一起(即使这样是多余的),方便看清程序的逻辑。
除了正常的判断语句,关键词if还可以写到一行中:

if构成了这样的一个表达式:
<value1> if <condition> else <value2>
当条件<condition>满足时,表达式值为<value1>,否则为<value2>。
2.3.2 循环
循环(Loop)的作用是将一段代码重复执行多次。
在Python中,循环结构主要有以下两种结构:while循环和for循环。
1. while循环
while循环的基本形式为:

Python执行<statesments>代码块,直到条件<condition>不满足为止。
例如,我们用while循环来计算数字1到99999的和:

循环在i等于100000停止。
再如,我们可以用列表作为循环的判断条件,在循环中每次抛出列表中的一个元素,直到列表为空,因为空的列表会被当作False:

2. for循环
for循环是Python中另一种实现循环的形式,其结构为:

for循环与while循环不同的地方在于,for循环是遍历一个序列<sequence>,每次将遍历得到的值放入变量<variable>中,而while循环则是执行到条件不满足为止。可以被for循环的序列包括有序序列和无序序列。
例如,列表是一种有序序列,所以上面的例子用for循环可改写成:


for循环每次从列表country中取出一个元素,赋给变量c,然后在循环中处理c。for循环在列表中所有的元素都被遍历完时结束。
我们用for循环实现数字1到99999的和的计算:

range()函数可以用来生成一个连续的整数列表,其基本用法如下:
● range(stop):生成从0开始到stop-1的整数组成的列表;
● range(start, stop):生成从start开始到stop-1的整数组成的列表;
● range(start, stop, step):生成从start开始到stop-1,间隔为step的整数组成的列表。
几个range()函数的例子:

3. 不同类型序列的for循环遍历
除了列表,其他的序列也支持使用for循环进行遍历。
有序序列,包括字符串、列表、元组等的遍历方式,都是按顺序从第一个元素开始进行遍历,如元组:

无序序列,如集合、字典等,按照某种设定的内部顺序进行for循环遍历,这种顺序不一定是有序的,如集合:


字典的for循环会按照键的某种顺序进行遍历:

如果想要同时得到字典的键对应的值,可以使用以下两种方式。
第一种是用索引:

第二种是使用.items()方法进行遍历:

事实上,.items()方法返回的值为:
In [23]: values.items()
Out[23]: [(1, 'one'), (2, 'two'), (3, 'three')]
for循环使用多变量赋值机制将键值对分别赋值给了k和v。
4. continue和break
continue和break都是循环中用来执行特定功能的关键字。这两个关键字通常与判断语句一起使用,用来处理循环中的一些特殊情况。在执行某次循环时,如果遇到continue,程序停止执行这次循环,直接开始下一次循环。
例如,在遍历列表时,我们使用continue来忽略所有的奇数值:


在循环的过程,如果i为奇数(即除2的余数不为0),continue后面的print语句会被跳过,直接循环下一个i;如果i为偶数,continue语句不会被执行,因此会打印出相应的结果。
在执行某次循环时,如果遇到break,不管循环条件是否满足,也不管序列是否已经被遍历完毕,程序都会从这个地方停止,并跳出循环。
例如,在遍历列表时,当列表中有大于10的值时,停止循环:

在循环的过程中,如果i大于10,break语句被执行。
除了for循环,continue和break语句也可以在while循环使用。循环和判断都可以多层嵌套,即判断中可以有新的判断或循环,循环中可以有新的循环,对于continue和break语句来说,它们只对当前的循环有效,对更外层的循环不起作用。
5. 循环中的else语句
while循环和for循环的后面可以跟else语句,这种else语句要和关键字break一起连用。循环后的else语句在break没被触发时执行。
例如,我们在上面的例子中加入else语句:

当break没有被执行时,else语句被执行:


6. 列表推导式
假设我们要得到一组数的平方,一个简单的想法是使用循环实现:

Python提供了列表推导式(List Comprehension)的机制,使用更简单的方式来创建这个列表:
In [34]: [x ** 2 for x in values]
Out[34]: [100, 441, 16, 49, 144]
列表推导式的基本形式是使用一个for循环,对序列的元素依次进行操作得到另一个序列。在上面的例子中,这个操作是对values中的每个值进行平方。列表推导式的最后还可以加入判断语句,实现对序列中的元素进行筛选。
例如,只保留列表中不大于10的数的平方:
In [35]: [x ** 2 for x in values if x <= 10]
Out[35]: [100, 16, 49]
字典也可以用推导式生成,只不过要写成“k: v”键值对的形式:
In [36]: {x: x**2 for x in values if x <= 10}
Out[36]: {10: 100, 4: 16, 7: 49}
7. enumerate()和zip()函数
在Python中,enumerate()函数和zip()函数常与for循环一起使用。
for循环会直接遍历容器类型中的元素:


有时候,我们希望在得到这些元素的同时,也得到相应的位置信息。
Python提供了enumerate()的函数来实现这样的功能,其用法为:

enumerate()函数在for循环的每一轮会将一个(index, value)组成的元组分别传给i和n。如果只需要位置信息,我们可以利用range()函数和len()函数相结合:

在for循环中另一个常用的函数是zip()函数,用法为:
zip(seq1 [, seq2 [...]]) -> [(seq1[0], seq2[0] ...), (...)]
它接受多个序列,返回一个元组列表。该列表的第i个元素是一个元组,由所有序列的第i个元素组成:

我们可以这样用for循环迭代zip()函数返回的结果:

对于zip()函数来说:
● 接受的序列可以是列表,也可以是其他类型的序列;
● 可以接受两个或以上的序列;
● 当序列的长度不同时,zip()函数返回的长度与序列中最短的一个相同。
例如,接受第三个序列,字典z:


如果参数是字典,zip()函数会保留它的键:
