为避免出现前述示例所示的繁琐代码,像下面这样做则很有帮助:
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'] 。