为避免出现前述示例所示的繁琐代码,像下面这样做则很有帮助:
x = 1
while x <= 100:
print(x, end = ',')
x += 1
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,
利用 while
语句,可以让一个代码块一遍又一遍的执行。
只要 while
语句的条件为 True
,
while
子句中的代码就会执行。
在代码中, while
语句总是包含下面几部分:
- 关键字;
- 条件(求值为
True
或False
的表达式); - 冒号;
- 从新行开始,缩进的代码块(称为
while
子句)。
那么如何使用Python来实现的?猜对了,就像上面那样做, 还可以使用循环来确保用户输入名字,如下所示:
# name = ''
# while not name:
# name = input('Please enter your name: ')
# print('Hello, {}!'.format(name))
请将以上代码注释去掉,尝试运行这些代码,并在要求输入名字时直接按回车键, 即会看到提示信息再次出现, 因为name还是为空字符串,这相当于假。
提示:如果只是输入一个空格字符(将其作为名字),结果将如何呢?试试看。
程序将 接受这个名字,因为包含一个空格字符的字符串不是空的,因此不会将name视为假。
这无疑是这个小程序的一个瑕疵,但很容易修复:
只需将while not name
改为while not name or name.isspace()
或while not name.strip()
即可。
while语句非常灵活,可用于在条件为真时反复执行代码块。这在通常情况下很好, 但有时可能想根据需要进行定制。一种这样的需求是为序列(或其他可迭代对象)中每个元素执行 代码块。
注意:基本上,可迭代对象是可使用for循环进行遍历的对象。 后面将详细介绍可迭代对象和 迭代器。就目前而言,只需将可迭代对象视为序列即可。
为此,可使用 for
语句:
words = ['this', 'is', 'an', 'ex', 'parrot']
for word in words:
print(word, end = ' | ')
this | is | an | ex | parrot |
或
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
for number in numbers:
print(number, end=',')
0,1,2,3,4,5,6,7,8,9,
鉴于迭代(也就是遍历)特定范围内的数是一种常见的任务,Python提供了一个创建范围的内置函数。
range(0, 10)
range(0, 10)
list(range(0, 10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
范围类似于切片。它们包含起始位置(这里为0),但不包含结束位置(这里为10)。 在很多情况下,都希望范围的起始位置为0。实际上,如果只提供了一个位置, 将把这个位置视为结 束位置,并假定起始位置为0。
range(10)
range(0, 10)
下面的程序打印数1~100:
for number in range(1,101):
print(number, end = ',')
1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,
注意,相比前面使用的while循环,这些代码要紧凑得多。
提示:只要能够使用 for
循环,就不要使用 while
循环。
要遍历字典的所有关键字,可像遍历序列那样使用普通的 for
语句。
d = {'x': 1, 'y': 2, 'z': 3}
for key in d:
print(key, 'corresponds to', d[key])
x corresponds to 1 y corresponds to 2 z corresponds to 3
也可使用 keys
等字典方法来获取所有的键。如果只对值感兴趣,可使用 d.values
,
d.items
以元组的方式返回键-值对。for
循环的优点之一是,可在其中使用序列解包。
for key, value in d.items():
print(key, 'corresponds to', value)
x corresponds to 1 y corresponds to 2 z corresponds to 3
注意 字典元素的排列顺序是不确定的。换而言之,迭代字典的键或值时, 一定会处理所有的键或值,但不知道处理的顺序。如果顺序很重要, 可将键或值存储在一个列表中并对列 表排序,再进行迭代。要让映射记住其项的插入顺序, 可使用模块collections中的 OrderedDict类。
Python提供了多个可帮助迭代序列(或其他可迭代对象)的函数, 其中一些位于第10章将介 绍的模块itertools中,但还有一些内置函数使用起来也很方便。
有时候可能想同时迭代两个序列。假设有下面两个列表:
names = ['anne', 'beth', 'george', 'damon']
ages = [12, 45, 32, 102]
如果要打印名字和对应的年龄,可以像下面这样做:
for i in range(len(names)):
print(names[i], 'is', ages[i], 'years old')
anne is 12 years old beth is 45 years old george is 32 years old damon is 102 years old
i
是用作循环索引的变量的标准名称。
一个很有用的并行迭代工具是内置函数 zip
,它将两个序列“缝合”起来,
并返回一个由元组组成的序列。返回值是一个适合迭代的对象,要查看其内容,
可使用 list()
将其转换为列表。
list(zip(names, ages))
[('anne', 12), ('beth', 45), ('george', 32), ('damon', 102)]
“缝合”后,可在循环中将元组解包。
for name, age in zip(names, ages):
print(name, 'is', age, 'years old')
anne is 12 years old beth is 45 years old george is 32 years old damon is 102 years old
函数zip
可用于“缝合”任意数量的序列。需要指出的是,当序列的长度不同时,
函数zip
将在最短的序列用完后停止“缝合”。
list(zip(range(5), range(100000000)))
[(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)]
在有些情况下,需要在迭代对象序列的同时获取当前对象的索引。 例如,可能想替换一个字符串列表中所有包含子串'xxx'的字符串。 当然,完成这种任务的方法有很多,但这里假设要像下面这样做:
strings='adfasdfasdfsfaesfasdfa'
for string in strings:
if 'xxx' in string:
index = strings.index(string) # 在字符串列表中查找字符串
strings[index] = '[censored]'
这可行,但替换前的搜索好像没有必要。另外,如果没有替换, 搜索返回的索引可能不对(即返回的是该字符串首次出现处的索引)。 下面是一种更佳的解决方案:
index = 0
for string in strings:
if 'xxx' in string:
strings[index] = '[censored]'
index += 1
这个解决方案虽然可以接受,但看起来也有点笨拙。 另一种解决方案是使用内置函数enumerate。
for index, string in enumerate(strings):
if 'xxx' in string:
strings[index] = '[censored]'
这个函数能够迭代索引-值对,其中的索引是自动提供的。
来看另外两个很有用的函数: reversed()
和 sorted()
。
它们类似于列表方法 reverse()
和 sort()
( sorted()
接受的参数也与 sort()
类似),
但可用于任何序列或可迭代的对象,且不就地修改对象,而是返回反转和排序后的版本。
sorted([4, 3, 6, 8, 3])
[3, 3, 4, 6, 8]
sorted('Hello, world!')
[' ', '!', ',', 'H', 'd', 'e', 'l', 'l', 'l', 'o', 'o', 'r', 'w']
list(reversed('Hello, world!'))
['!', 'd', 'l', 'r', 'o', 'w', ' ', ',', 'o', 'l', 'l', 'e', 'H']
''.join(reversed('Hello, world!'))
'!dlrow ,olleH'
请注意,sorted
返回一个列表,而 reversed
像zip那样返回一个更神秘的可迭代对象。
无需关心这到底意味着什么,只管在 for
循环或 join
等方法中使用它,不会出现任何问题。
只是不能对它执行索引或切片操作,也不能直接对它调用列表的方法。要执行这些操作,
可先使用 list
对 返回的对象进行转换。
提示: 要按字母表排序,可先转换为小写。为此,
可将 sort
或 sorted
的 key
参数设置为 str.lower
。
例如,sorted("aBc", key=str.lower)
返回 ['a', 'B', 'c']
。