第五章 列表:遍历
遍历整个列表
为何需要循环
任务:为何需要循环?
假设有一个班级名单(列表),需要将其中每个同学名字都打印出来,并对他/她说一句问候语。按之前学到的Python知识,可以分别地(依次)获取名单中的每个名字,但这种做法会导致多个问题:
- 如果名单很长,为每个人写问候语,将包含大量重复的代码。
- 列表可以动态增减,每当名单的长度发生变化时,都必须对代码进行增减,不易维护。
- 重复性的工作。
为解决上述问题,需要使用循环技术。
循环让我们可以对列表的每个元素都采取一系列相同(重复性)的操作,从而高效地处理任何长度的列表,包括包含数千乃至数百万个元素的列表。
任务:掌握for循环语法
知识点:
- 遍历就是从头到尾依次从列表中获取数据(元素),然后在循环体内部对每个元素执行相同操作。
- 为实现遍历,Python引入
for
循环(for-each)机制。- 为了提高列表的遍历效率,Python专门提供了迭代器
iteration
来实现遍历功能。关于迭代器后续会讲解,这里仅作了解。
知识点:
for
循环语法。
描述:
for
循环用于迭代/遍历序列对象(即列表,元组,字典或字符串)。通过使用for
循环,可以对序列中的每个元素执行一系列重复的语句/操作。语法:
1
2
3
4
5 for item in sequence:
statements(item)
for 临时变量 in 序列对象(比如列表):
循环体语句块(必须相同的缩进)
知识点(术语):何谓迭代?
- 迭代:每运行一次循环体
statements
,称迭代一次。- 迭代次数:循环共运行了几次。
- 迭代条件:满足循环的条件。
任务:列表的应用场合分析
知识点:
尽管
Python
列表中可以存储不同类型的数据。但是在开发中,更多的应用场景是
- 列表存储相同类型的数据。
- 通过迭代遍历,在循环体内部,针对列表中的每一项元素,执行相同的操作。
深入列表for循环
任务:for循环的注意事项
for
循环注意事项:
- 在循环体语句块中,执行重复代码。
- C++或Java使用
{ }
来管理语句块,所以他们对缩进不敏感。- Python敏感于代码缩进。它通过代码缩进,来管理和识别语句块。
- 同个语句块代码需要采用相同的缩进量,如果不恰当的使用缩进,将会报错。
- 请善用代码排版插件小锤子。
- 这种遍历适用于任何序列对象(不局限于列表)。
任务:循环通过缩进标识循环体
在程序设计中,循环是一项非常重要的技术,因为它可以让计算机自动完成重复工作。
知识点:
循环意义:在每次迭代过程中,依次从列表
numbers
中取出元素,并赋值给临时变量(局部)val
,然后再对每个val
执行相应的操作。Python循环语法:循环体通过缩进被Python解释器识别。
- 循环体的前后,多敲一个回车空行。
- 通过循环体内与循环体外的相对缩进,来标识循环语句块。
1 | print('----求解列表元素之和----') |
任务:for循环的临时变量为局部变量
知识点:
- 在循环体中,对循环体内的局部变量进行修改,不会影响原列表的元素值。
- 例如,
for val in numbers:
对val
进行修改,不影响numbers
的值。val
是局部变量,作用域只限制于循环体。
1 | numbers = [6, 5, 3, 8, 4, 2, 5, 4, 11] |
任务:通过临时变量实现批量运算
知识点:
- 循环的目的是对一组数据实现批量重复性操作。
- 在循环体内,通过对局部变量进行运算和操作,对列表元素实现批量地重复性操作。
1 | names = ['alice', 'david', 'carolina'] |
代码解析:
- 首先,定义了一个列表。
- 接下来,定义一个
for
循环;这行代码让Python从列表names
中取出一个名字,并将其存储在变量name
中。 - 最后,让Python打印前面存储到变量
name
中的名字。这样,对于列表中的每个名字,Python都将重复执行循环体代码。
习题
第一题
题目要求:
- 创建字符串”hello, python”,遍历打印每个字符。
代码如下:
1 | massage="hello,python" |
运行结果:
1 | h e l l o , p y t h o n |
第二题
题目要求:
- 输入一个水果的列表,遍历打印每种水果。
代码如下:
1 | FruitsList=["apple","banana","pear"] |
运行结果:
1 | apple |
for循环体包含多条语句
任务:for循环体使用多条语句
之前的循环体都是一行代码,在本节将循环体扩展为多行。在for
循环中,可对每个元素执行任何操作。
知识点:
- Python解释器使用缩进来判断循环体语句块的范围。
- 从
for
的声明之后到遇到第一个与for
同级别缩进的语句。- 例如,在
for name in names
后面,每个缩进的代码行都是循环体部分,这部分的代码将针对列表中的元素都执行一次。
1 | names = ['alice', 'david', 'carolina'] |
for循环结束的标志(易错)
任务:for循环结束标志
for
循环结束后再怎么做呢?通常,需要提供总结性输出或接着执行程序必须完成的其他任务。
知识点:与
for
同级别缩进的代码不属于循环体代码,它们只执行一次,而不会重复执行。
例子:首先在循环体为每个成员打印2条消息;然后,在循环结束之后,输出1条总结性的消息,需要将相应的代码放在与for
同级别缩进处:
1 | names = ['alice', 'david', 'carolina'] |
任务:循环体通过缩进进行标识
知识点:多重循环,用缩进来识别每重
for
的循环体语句块范围。
1 | numbers = [1,2,3,4] |
代码解析:
两个嵌套的
for
循环。过程类似于C语言。外层循环体包括:整个内层循环+
print('')
。程序步骤如下:
- 首先,在外层循环取列表
numbers
第一个元素1赋值给val1
。 - 然后,进入内层循环,依次取列表
numbers
赋值给val2
。并执行内层循环体print(val1*val2, end = ' ')
。 - 内层循环结束后,返回到外层循环,执行
print('')
。 - 此时,外层循环被完整地执行一次。Python再次检测外循环是否遍历完所有元素,如果否则再次执行循环。
- 首先,在外层循环取列表
print()
中的end
参数:在输出的结尾加入一个end
字符,默认为换行符。end = ' '
表示print()
函数最后输出加``空格符。各位可以参数修改end
参数,观察结果。print('')
:输出换行。因为end
参数的默认值是换行符。输出空字符,则代表对当前输出进行换行。
习题
第三题
题目要求:
想出至少三种你喜欢的比萨,将其名称存储在一个列表中,再使用for
循环将每种比萨的名称都打印出来。
- 修改这个
for
循环,使其打印包含比萨名称的句子,而不仅仅是比萨的名称。对于每种比萨,都显示一行输出,如“I like pepperoni pizza”。 - 在程序的循环结束后,添加一行代码,输出总结性的语句,如“I really love pizza!”。
代码如下:
1 | PizzaList=["pepperoni","Chicago-Style","California-style","Bar"] |
运行结果:
1 | pepperoni |
第四题
题目要求:
- 想出至少三种有共同特征的动物,将这些动物的名称存储在一个列表中,再使用
for
循环将每种动物的名称都打印出来。- 修改这个程序,使其针对每种动物都打印一个句子,如“A dog would make a great pet”。
- 在程序末尾添加一行代码,指出这些动物的共同之处,如打印诸如“Any of these animals would make a great pet!”这样的句子。
代码如下:
1 | AnimalList=["dog","cat","bird"] |
运行结果:
1 | dog |
常见的缩进错误
知识点:
Python根据缩进来判断代码行与前一个代码行的关系。
- 比如
for
循环用缩进来识别语句块范围。 - 同样适用于后的
while
循环、if
判断、def
函数和class
类的定义等。
- 比如
正确的使用Python的缩进技术,非常重要。
Python通过使用缩进让代码更易读;简单地说,它要求你使用缩进让代码整洁而结构清晰。
通过代码不同程度的缩进,可以快速的掌握程序的组织结构。
任务:忘记缩进(错误)
知识点:
- 对于位于
for
语句:
之后循环体代码,一定要缩进。- 如果忘记缩进,Python解释器将会提示错误。
1 | names = ['alice', 'david', 'carolina'] |
任务:忘记缩进额外的代码行(错误)
知识点:
- 解释器只检测
for
语句头之后的第一句是否缩进。- 非第一句的循环体语句,Python无法检测,这将会发生逻辑错误:代码可以运行,结果出乎意料。
1 | names = ['alice', 'david', 'carolina'] |
程序解析:
- 第二条
print
语句原本需要缩进,但Python发现for
语句后面有一行代码是缩进的,因此它没有报告错误。 - 程序结果是,对于列表中的成员,都执行了第一条
print
语句,因为它缩进了;而第二条print
语句没有缩进,因此它只在循环结束后执行一次。 - 由于变量
name
的终值为'carolina'
,因此只有她收到了消息“Thanks for your show, Carolina.”。
任务:非语句块的不必要缩进(错误)
知识点:
非循环体(代码块)的代码不要缩进,否则将会发生语法或逻辑错误。
代码块标志是什么?
- 在冒号
:
之后,需要用缩进来标识代码块范围。- 代码块范围:冒号
:
之后代码 到 第一行与for
同级别缩进的代码。- 为优雅的区分代码块代码,请在代码块结束后多加一个换行。
1 | message = "Hello Python world!" |
任务:同一级别的代码必须使用统一缩进
知识点:同一级别代码的缩进规则。
允许:同一级别的代码必须要采用统一的缩进,不管缩进多少个空格。
不允许:但Python不允许它们采用不同统一缩进。
- 建议第一级别的代码顶格写,之后凡是遇到语句块再依次缩进。
- 比如二重循环,第二层循环语句块需要缩进两个级别。
1 | print("允许同一级别的代码都采用统一的缩进") |
1 | print("不允许同一级别的代码采用不同统一的缩进") |
第一个代码块,代码虽然不顶格,但是同一级别采用相同缩进方式,所以代码可以正常运行;第二代码块,将会触发缩进错误。
任务:语句块之后不必要的缩进(错误)
知识点:
- 循环体语句块之后的代码,如果不恰当的使用了缩进,Python将会视它为语句块代码,将会发生语法错误或逻辑错误。
- 有些缩进问题是语法错误,Python解释器会报错误,可通过报错代码,找到出错原因。
- 但是很多缩进问题是逻辑错误,Python不会报逻辑错误,程序一般都能正常运行。因此,排查逻辑错误,通常需要花更多的时间。
- Python的语句块缩进很容易造成初学者逻辑错误,因此一定要小心使用。
例子:不小心缩进了应在循环结束后执行的代码,这些代码将针对每个列表元素重复执行。
1 | names = ['alice', 'david', 'carolina'] |
任务:遗漏冒号
知识点:
代码块的标志是什么?在冒号
:
之后,需要用缩进来标识代码块范围。如果遗漏了
:
,Python将无法判断哪里是语句块的开始,那么将会报错。这个错误是语法错误,相信Python肯定会报的。
1 | names = ['alice', 'david', 'carolina'] |
数值数列
任务:序列类型或容器类型
知识点:什么叫序列类型?
序列是Python中最基本的数据结构,它是容器类型的数据类型。
序列中的每个元素都分配了一个称为索引的整数(用于指明元素位置)。
- 例如,第一个索引是0,第二个索引是1,依此类推。
Python有6个序列的内置类型,但最常见的是列表、元组和字符串。
很多应用都会涉及到处理和储存一组数值类型的数据。例如,在游戏中,需要跟踪每个角色的位置信息,还可能需要对玩家进行积分排行。
知识点:
- 类似于C语言中的数组,在Python中,可使用列表
list
来管理一组数值类型的数据。- 列表是一种Python序列类型(容器类型),它提供了很多便捷的方法来处理和维护数据(列表元素)。
- 即使列表包含数百万个元素,也可以很高效的处理。
使用函数range()生成数值序列
任务:range()数值序列生成函数
知识点:
语法:
range(stop)
或range(start, stop[, step])
描述:
range()
函数生成一个从start
开始到stop
(但不包括)按step
步长的整形序列(非列表)。Python内置函数,一般用在for
循环中。参数:
start
: 从start
开始。默认值为0。例如range(5)
等价于range(0,5)
。stop
: 到stop
结束,但不包括stop
。例如:range(0,5)
是[0, 1, 2, 3, 4]
不包括5。step
:步长,默认值为1。例如:range(0,5)
等价于range(0,5,1)
。返回:一个
range
对象。而不是列表类型,所以调用print()
时,不会直接打印序列元素。限制:只能生成整数序列。
1 | num = range(1, 5, 1) |
任务:print()的end参数使用
知识点:
print()
函数的参数end ='字符'
指定end
参数的默认值为换行符\n
。
1 | for value in range(1, 5, 1): |
1 | for value in range(1, 5, 1): |
- 注意,
range()
只生成了1~4
,并非想象中的1~5
。 - 函数
range()
让Python从start
到stop-1
范围创建整数序列,不包括stop
值。 - 使用
range()
时,如果输出结果不符合预期,请尝试将对参数值进行加1或减1尝试。
任务:range()函数参数不能为空
知识点:
range()
的3个参数只能为整形,不能为浮点数。- 否则就会出错。
1 | # 任意一个参数为浮点数会报错 |
任务:range()函数的等价形式
知识点:
range(n)
等价于range(0,n,1)
。
1 | for value in range(6): |
知识点:
- 为生成浮点数序列,可将
range()
生成的整数序列。 - 然后,除以特定的数,得到等间隔的小数序列。
1 | for value in range(1, 10, 2): |
任务:通过遍历或索引获取range()
序列元素
知识点:深入解析
range()
函数。
range()
被创建时,在内存中不直接生成所有的序列元素。- 元素只有在使用时,比如遍历或索引访问时,才会在内存中被生成。
- 这种方式可以大大的降低程序对内存的使用。
通过索引或循环来遍历来访问range()
序列元素。
1 | num = range(1,10, 2) |
任务:使用list()将range对象转换为列表
知识点:
- 通过
list()
函数可以将range()
对象的所有元素转换为列表。- 返回数值类型的列表。
习题
第六题
题目要求:
- 计算1到100的整数之和,奇数之和,偶数之和。
代码如下:
1 | ListNum=range(1,101,1) |
运行结果:
1 | 5050 2500 2550 |
第七题
题目要求:
- 输入两个整数
a
和b
,计算区间[a b]
整数之和。
代码如下:
1 | a=int(input()) |
运行结果:
1 | 2500 |
第八题
题目要求:
- 输入两个数,求最大公约数和最小公倍数。提示:使用
for
循环,和range()
代码如下:
1 | num1 = int(input('Num1:')) |
运行结果:
1 | 3和27的最大公约数为:3 |
第九题
题目要求:
- 生成一个列表,列表元素分别为[12,22,32…n2]。
代码如下:
1 | n=int(input('项数')) |
运行结果:
1 | 12 |
第十题
题目要求:
- 找出1~10之间所有偶数,返回一个列表,包含以这个偶数为半径的圆的面积。
代码如下:
1 | pi=3.14 |
运行结果:
1 | 2 12.56 |
使用range()输出乘法表
任务:使用range()输出乘法表
知识点:
print()
函数的参数end ='字符'
指定- 它的默认为换行符
\n
。
使用双重循环,并通过print()
语句输出乘法表。
1 | for i in range(1, 4): |
- 循环体的核心语句
print(i,'*', j,'=', i * j, end=" ")
,输出每个乘法结果。 - 这个
print()
语句为输出乘法算式结果,共用了6个字符串拼接,以,
相隔。
上述的输出语句非常复杂,那么Python是否提供更好的解决方案?.format()
字符串格式函数。
任务:.format()
函数的乘法表
使用.format()
函数来格式化输出乘法表。
1 | for i in range(1, 4): |
使用list()转换数字列表
任务:使用list()将range对象转换为列表
知识点:
- 由于
range()
数字序列生成器,不能直接在内存中生成数字列表,只有元素被使用时,才会生成数字。- 可以通过
list()
函数可以将range
对象的所有元素转换为列表,返回数值类型的列表。- 将
range()
返回作为list()
函数的参数:list(range(10))
。list
类型的数据,在内存中真实存在;range
类型的数据,在内存中不存在(不占内存)。
1 | # range()数字序列生成器,无论多大的数据都不占内存 |
使用函数
range()
时,还可指定step
步长。
例如,下面的代码打印1~10内的偶数,函数range()
从start=2
开始,然后不断地加step=2
,直到达到或超过stop
(11)。
1 | even_numbers = list(range(2, 11, 2)) |
任务:两种生成平方数列表的方式
使用函数range()
几乎能够创建任何需要的数字序列。
例如,创建一个包含前10个整数的平方数序列。在Python中,两个星号**
表示乘方运算。下面的代码演示了如何将前10个整数的平方通过循环逐个加到squares
列表中:
1 | squares = [] |
程序解析:
- 首先,创建了一个空列表
squares
。 - 接下来,使用函数
range()
让Python遍历1~10的值。 - 在循环中,计算当前值的平方,并将结果
append()
到变量square
中。 - 然后,将新计算得到的平方值附加到列表
squares
末尾。 - 最后,循环结束后,打印列表
squares
。
为让这些代码更简洁,在循环体中可不使用临时变量square
,而是直接将每个平方结果附加到列表末尾:
1 | squares = [] |
创建更复杂的列表时,可使用上述的两种方法。
- 作为新手,建议使用第1中方式,通过使用临时变量会让代码更易读。
- 熟悉之后,可以使用第二种更简便的方式,降低代码冗余度。
统计列表的信息
任务:列表的信息统计
Python提供了几个专门用于处理列表元素的内建(build-in)函数,即python自带函数。
知识点:
min()
方法返回列表元素中的最小值。max()
方法返回列表元素中的最大值。sum()
方法返回列表元素之和。
1 | digits = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0] |
知识点:字符串列表的最小和最大值。
min()
和max()
同样适合字符串列表。- 字符串列表的元素比较,先比第一位,如果相同,则再比第二位。以此类推。
1 | list1 = ['113', '11111', '1122'] |
习题
第十一题
题目要求:
- 使用一个
for
循环打印数字1~20(包含)。
代码如下:
1 | for num in range(1,21,1): |
运行结果:
1 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
第十二题
题目要求:
- 创建一个列表,其中包含数字1~1 000 000,再使用一个
for
循环将这些数字打印出来(如果输出的时间太长,按Ctrl + C停止输出,或关闭输出窗口)。
代码如下:
1 | for num in range(1,1000000,1): |
运行结果:
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 ...... |
第十三题
题目要求:
- 创建一个列表,其中包含数字1~1 000 000,再使用
min()
和max()
核实该列表确实是从1开始,到1 000 000结束的。另外,对这个列表调用函数sum()
,看看Python将一百万个数字相加需要多长时间。
代码如下:
1 | List=range(1,1000001,1) |
运行结果:
1 | 1 |
第十四题
题目要求:
- 通过给函数
range()
指定第三个参数来创建一个列表,其中包含1~20的奇数;再使用一个for
循环将这些数字都打印出来。
代码如下:
1 | mylist=range(1,20,2) |
运行结果:
1 | 1 3 5 7 9 11 13 15 17 19 |
枚举:遍历列表的索引
认识可迭代对象
任务:可迭代对象
知识点:
为何列表可以直接使用
for-in
语句来遍历元素?
- 因为它是黑科技,可迭代对象。
列表可以直接遍历获得列表元素,而不像C++或Java是通过下标索引方式来遍历列表。
for
循环并非只限于列表,任何可迭代对象都可使用此功能。
知识点:何谓可迭代对象?(只需要了解基本概念,不需要深入)
可以被遍历的对象,任何可以用
for-in
语句来获取元素的对象都是可迭代对象。即,
1
2 for iterating_var in sequence:
statements(s)描述:可迭代对象每次循环(迭代)返回一个元素,直到遍历完所有的元素(迭代结束)。
常见可迭代对象:
list
列表对象,str
字符串对象,range
对象。
1 | my_list = ['dog', 'cat', 'pig'] |
任务:如何判断某个对象为可迭代对象?
知识点:
- 通过
isinstance(a, Iterable)
方式来判断变量a
是否为可迭代对象。- 需要从
collections
模块中导入Iterable
。
1 | from collections import Iterable |
两种获取元素索引的方式
知识点:
- 在
for-in
循环体中,并不能直接获得列表元素所对应的索引。- 只能遍历获取元素,但并不知元素在列表中的位置。
为此,下面给出了两种类似C++的for
循环方式来同时获得元素索引。
任务:如何获得for
循环元素索引?
方法一:设置循环的临时变量i
为下标索引。
1 | my_list = ['dog', 'cat', 'pig'] |
程序解析:
range(len(my_list))
:对于函数的嵌套写法,应该从里函数len()
到外函数range()
的顺序来解读程序。- 这里使用
range()
函数,根据my_list
列表的长度len(my_list)
来构造索引序列。 - 此时的临时变量
i
为元素索引。因此,在循环体中,通过下标索引方式访问元素my_list[i]
。
方法二:引入额外变量来跟踪迭代过程。
1 | i = 0 |
程序解析:
- 在循环中,引入额外的变量
i
来跟踪当前循环的迭代情况。 i
即为列表元素的下标索引。
知识点(补充):
print()
的sep
参数,为多个字符串输出添加sep
所指定的分割符。
1 | print('hello', ': ', 'hello', sep='~~') |
enumerate()函数获取元素索引
任务:使用enumerate()
函数获得元素索引
为解决上述需求,python引入了一种更优雅的方案enumerate()
函数,能够在迭代列表的同时获取索引。
知识点:
语法:
enumerate(iterable, start=0)
,即
1
2 for index, item in enumerate(iterable, start=0):
indented_statements描述:内置函数,生成一系列
index-item
对(元组),其中index
是索引,而item
为当前元素。参数:
iterable
是之前提到的可迭代对象,可以被遍历的对象。参数:
start
自定义索引序号的起始值,默认值为0。每次迭代,enumerate()
返回的索引值index
= 元素item
原来的索引 + 起始值start
。
1 | my_list = ['dog', 'cat', 'pig'] |
使用.format()
格式化打印元素和序号,格式为:两位数序号.
+空格+四位数据
,右对齐。
1 | fib_list = [1, 2, 4, 5, 8, 13, 21, 34, 55, 89, 144] |
习题
第十五题
题目要求:
- 打印斐波那契数列
fib_list = [1、1、2、3、5、8、13、21、34]
,输出格式:“第i个元素为XXX”。 分别实现:
- 手工初始化
fib_list
,使用range()
函数打印斐波那契数列; - 手工初始化
fib_list
,使用enumerate()
函数打印斐波那契数列;
- 手工初始化
代码如下:
1 | fib_list = [1,1,2,3,5,8,3,21,34] |
运行结果:
1 | 第 0 个元素为 1 |
第十六题
题目要求:
- 斐波那契数列的格式化输出:通过
format()
格式化字符串输出。模板字符串3个位置索引参数,分别为前个元素、当前元素、当前元素与前一个元素的差;宽度分别设置为3、5、5字宽;由于第1个元素的前一个元素不存在,可以使用if
判断只打印索引值大于1的元素输出。
代码如下:
1 | fib_list = [1,1,2,3,5,8,3,21,34] |
运行结果:
1 | 1 1 0 |