>>> from env_helper import info; info()
页面更新时间: 2020-11-19 21:09:23
操作系统/OS: Linux-4.19.0-11-amd64-x86_64-with-debian-10.6 ;Python: 3.7.3

2.9. for循环和 range()函数

在条件为 True 时, while 循环就会继续循环(这是它的名称的由来)。但如果你 想让一个代码块执行固定次数,该怎么办?可以通过 for 循环语句和 range() 函数来 实现。

2.9.1. “类真”和“类假”的值

其他数据类型中的某些值,条件认为它们等价于 TrueFalse 。 在用于条件时,00.0''(空字符串)被认为是 False ,其他值被认为是 True 。 例如,请看下面的程序:

name = ''
while not name:
    print('Enter your name:')
name = input()
print('How many guests will you have?')
numOfGuests = int(input())
if numOfGuests:
    print('Be sure to have enough room for all your guests.')
    print('Done')

如果用户输入一个 S 字符串给 name,那么 while 语句的条件就会是 True , 程序继续要求输入名字。如果 numOfGuests 不是 0 ,那么条件就被认为是 True , 程序就会为用户打印一条提醒信息。

可以用 not name !='' 代替 not name ,用 numOfGuests != 0 代替 numOfGuests , 但使用类真和类假的值会让代码更容易阅读。

在代码中, for 语句看起来像 for i in range(5): 这样,总是包含以下部分:

  • for 关键字;

  • 一个变量名;

  • in 关键字;

  • 调用 range() 方法,最多传入3个参数;

  • 冒号;

  • 从下一行开始,缩退的代码块(称为 for 子句)。

让我们创建一个新的程序,看看 for 循环的效果。

>>> print('My name is')
>>> for i in range(5):
>>>     print('Jimmy Five Times (' + str(i) + ')')
My name is
Jimmy Five Times (0)
Jimmy Five Times (1)
Jimmy Five Times (2)
Jimmy Five Times (3)
Jimmy Five Times (4)

运行这个程序时,它将打印5次 Jimmy Five Timesi 的值,然后离开 for 循环。

也可以在循环中使用 continue 语句。continue 语句将让 for 循环变量继续下一个 值,就像程序执行已经到达循环的末尾并返回开始一样。实际上,只能在 whilefor 循环内部使用 continuebreak 语句。如果试图在别处使用这些语句, Python 将报错。

作为 for 循环的另一个例子,请考虑数学家高斯的故事。当高斯还是一个小孩 时,老师想给全班同学布置很多计算作业。老师让他们从 0 加到 100 。高斯想到了 一个聪明办法,在几秒钟内算出了答案,但你可以用 for 循环写一个 Python 程序, 替你完成计算。

>>> total = 0
>>> for num in range(101):
>>>      total = total + num
>>> print(total)
5050

结果应该是 5050 。程序刚开始时,total变量被设为 0 。然后 for 循环执行 100total  = total + num 。当循环完成 100 次迭代时,0100 的每个整数都加给了 total 。这时, total 被打印到屏幕上。即使在最慢的计算机上,这个程序也不用1秒钟就能 完成计算。

(小高斯想到,有50对数加起来是100: 1 +99,2 + 98,3 + 97……直到49+ 51。因为 50 × 100 是5000,再加上中间的50,所以0到100的所有数之和是5050。聪明的孩子!)

2.9.2. 等价的 while 循环

实际上可以用 while 循环来做和 for 循环同样的事, for 循环只是更简洁。让我 们用与 for 循环等价的 while 循环,重写 fiveTimes.py

>>> print('My name is')
>>> i = 0
>>> while i < 5:
>>>     print('Jimmy Five Times (' + str(i) + ')')
>>>     i = i + 1
My name is
Jimmy Five Times (0)
Jimmy Five Times (1)
Jimmy Five Times (2)
Jimmy Five Times (3)
Jimmy Five Times (4)

运行这个程序,输出应该和使用 for 循环的 fiveTimes.py 程序一样。

2.9.3. range() 的开始、停止和步长参数

某些函数可以用多个参数调用,参数之间用逗号分开,range() 就是其中之一。 这让你能够改变传递给 range() 的整数,实现各种整数序列,包括从 0 以外的值开始。

>>> for i in range(12, 16):
>>>     print(i)
12
13
14
15

第一个参数是 for 循环变量开始的值,第二个参数是上限,但不包含它,也就 是循环停止的数字。

range() 函数也可以有第三个参数。前两个参数分别是起始值和终止值,第三个 参数是“步长”。步长是每次迭代后循环变量增加的值。

>>> for i in range(0, 10, 2):
>>>     print(i)
0
2
4
6
8

所以调用 range(0, 10, 2) 将从 0 数到 8 ,间隔为 2

在为 for 循环生成序列数据方面, range() 函数很灵活。举例来说,甚至可以用 负数作为步长参数,让循环计数逐渐减少,而不是增加。

>>> for i in range(5, -1, -1):
>>>     print(i)
5
4
3
2
1
0

运行一个 for 循环,用 range(5, -1, -1) 来打印 i ,结果将从 5 降至 0

2.9.4. 简单推导

列表推导是一种从其他列表创建列表的方式,类似于数学中的集合推导。列表推导的工作原理非常简单,有点类似于for循环。

>>> [x * x for x in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

这个列表由range(10)内每个值的平方组成,非常简单吧?如果只想打印那些能被3整除的平方值,该如何办呢?可使用求模运算符:如果y能被3整除,y % 3将返回0(请注意,仅当x能被3 整除时,x*x才能被3整除)。为实现这种功能,可在列表推导中添加一条if语句。

>>> [x*x for x in range(10) if x % 3 == 0]
[0, 9, 36, 81]

还可添加更多的for部分。

>>> [(x, y) for x in range(3) for y in range(3)]
[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]

作为对比,下面的两个for循环创建同样的列表:

>>> result = []
>>> for x in range(3):
>>>     for y in range(3):
>>>         result.append((x, y))
>>> result
[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]

与以前一样,使用多个for部分时,也可添加if子句。

>>> girls = ['alice', 'bernice', 'clarice']
>>> boys = ['chris', 'arnold', 'bob']
>>> [b+'+'+g for b in boys for g in girls if b[0] == g[0]]
['chris+clarice', 'arnold+alice', 'bob+bernice']

这些代码将名字的首字母相同的男孩和女孩配对。

更佳的解决方案

前述男孩/女孩配对示例的效率不太高,因为它要检查每种可能的配对。使用Python解决 这个问题的方法有很多,下面是Alex Martelli推荐的解决方案:

>>> girls = ['alice', 'bernice', 'clarice']
>>> boys = ['chris', 'arnold', 'bob']
>>> letterGirls = {}
>>> for girl in girls:
>>>     letterGirls.setdefault(girl[0], []).append(girl)
>>> print([b+'+'+g for b in boys for g in letterGirls[b[0]]])
['chris+clarice', 'arnold+alice', 'bob+bernice']

这个程序创建一个名为letterGirls的字典,其中每项的键都是一个字母,而值为以这个 字母打头的女孩名字组成的列表(字典方法setdefault在前一章介绍过)。创建这个字典后, 列表推导遍历所有的男孩,并查找名字首字母与当前男孩相同的所有女孩。这样,这个列表 推导就无需尝试所有的男孩和女孩组合并检查他们的名字首字母是否相同了。

使用圆括号代替方括号并不能实现元组推导,而是将创建生成器,详细信息请参阅第9章的 旁注“简单生成器”。然而,可使用花括号来执行字典推导。

>>> squares = {i:"{} squared is {}".format(i, i**2) for i in range(10)}
>>> squares[8]
'8 squared is 64'

在列表推导中,for前面只有一个表达式,而在字典推导中,for前面有两个用冒号分隔的表达式。这两个表达式分别为键及其对应的值。‌