Python 中的许多内置函数会返回可迭代对象,因此遍历可迭代对象是一种常见操作。字符串、列表、元组、集合、字典以及 range()、map()、zip() 的返回值,都可以用 for...in 依次访问其中的每个元素。语法为 for element in iterable::element 代表当前元素,iterable 是可迭代对象。需要注意:map()、zip() 的返回值本身不是列表,直接打印往往看不到序列内容,必须先用 list() 转换成列表再输出。
内置函数 map() 接受两个参数:一个函数和一个可迭代对象。它将函数应用于可迭代对象中的每个元素,并返回一个新的可迭代对象,其元素为函数作用的结果。例如:
chengji = ['87', '95', '76', '84']
mapped = map(int, chengji)
print(list(mapped))
输出为 [87, 95, 76, 84],相当于把每个成绩字符串转换成整数。内置函数 zip() 接收两个或多个可迭代对象作为参数,将对应位置的元素配对形成一个元组,并把这些元组作为可迭代对象的元素返回。例如 names = ['Alice', 'Bob', 'Charlie'] 与 scores = [85, 92, 78],list(zip(names, scores)) 得到 [('Alice', 85), ('Bob', 92), ('Charlie', 78)]。
Python 遍历可迭代对象有三种方法。第一,用 for...in 直接遍历元素,适合只关心值、不关心位置的统计与筛选。例如例 2-7:求一个长度为 100 的随机整数列表中 3 的倍数有多少个,循环变量依次取每个元素 v,判断 v % 3 == 0 即可计数。第二,使用 enumerate()。仅用 for...in 能够访问全部元素,但很难掌握每个元素的索引;enumerate() 在遍历时同时获取索引和值,返回包含二者的元组,常用于需要同时访问元素及其索引的场景。例如例 2-8:一个列表保存 50 名学生的成绩,输出序号与成绩可用 for i, v in enumerate(a): print(i+1, v)。因为第一个元素的索引是 0,给它加 1 以表示学号。第三,依次遍历可迭代对象的索引,用 while 和 for...in 均可,常见写法是 for i in range(len(a))。当必须修改原列表中的元素时,应采用这种方法。
常见坑是:在用 for...in 或 enumerate() 时,修改遍历的变量不能作用于原来的列表。例 2-9 要求将一个整数列表中的每个元素变成原来的 2 倍。若写成 for v in a: v *= 2,循环之前和之后输出的列表相同,原因是 v *= 2 只把变量 v 变成了原来的 2 倍,并没有改变列表中的元素。正确做法是用 len() 计算列表长度,用 range() 生成代表索引的可迭代对象:for i in range(len(a)): a[i] *= 2。此外,不要把 enumerate 得到的 0 起始索引直接当作序号,也不要忘记将 map、zip 的结果转换成列表后再查看内容。
for element in iterable: 依次访问每个元素。map(函数, 可迭代对象):把函数作用于每个元素,返回新的可迭代对象;常用 list() 查看内容。zip(可迭代对象1, 可迭代对象2, ...):将对应位置的元素配对成元组,返回可迭代对象。for...in 直接遍历元素;② enumerate() 同时得到索引和值;③ 依次遍历索引(while 或 for i in range(len(a)))。enumerate() 的第一个元素索引为 0;作序号、学号时通常写 i+1。for...in 或 enumerate() 时,修改循环变量不能改变原列表;要改原列表须通过索引,如 a[i] *= 2。