在条件为 True
时, while
循环就会继续循环(这是它名称的由来)。
但如果想让一个代码块执行固定次数,该怎么办?
可以通过 for
循环语句和 range()
函数来实现。
# 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 Times
和 i
的值,然后离开 for
循环。
也可以在循环中使用 continue
语句。continue
语句将让 for
循环变量继续下一个值,
就像程序执行已经到达循环的末尾并返回开始一样。实际上,
只能在 while
和for
循环内部使用 continue
和 break
语句。
如果试图在别处使用这些语句, Python
将报错。
作为 for
循环的另一个例子,请考虑数学家高斯的故事。当高斯还是一个小孩时,
老师想给全班同学布置很多计算作业。老师让他们从 0
加到 100
。
高斯想到了一个聪明办法,在几秒钟内算出了答案,但可以用 for
循环写一个 Python
程序,
代替完成计算。
total = 0
for num in range(101):
total = total + num
print(total)
5050
结果应该是 5050
。程序刚开始时,total
变量被设为 0
。
for
循环执行 100
次 total = total + num
。
当循环完成 100
次迭代时,0
到 100
的每个整数都加给了 total
。
这时, total
被打印到屏幕上。即使在最慢的计算机上,
这个程序也不用1秒钟就能完成计算。
(小高斯想到,有50对数加起来是100: 1 +99,2 + 98,3 + 97......直到49+51。
因为 50 × 100
是5000,再加上中间的50,所以0到100的所有数之和是5050。聪明的孩子!)
实际上可以用 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)
某些函数可以用多个参数调用,参数之间用逗号分开,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
。
列表推导是一种从其他列表创建列表的方式,类似于数学中的集合推导。
列表推导的工作原理非常简单,有点类似于 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前面有两个用冒号分隔的表达式。这两个表达式分别为键及其对应的值。