前言
一、遍历整个列表
深入研究循环
在for循环中执行更多操作
在for循环结束后执行一些操作
二、避免缩进错误
忘记缩进
忘记缩进额外的代码行
不必要的缩进
循环后不必要的缩进
遗漏了冒号
三、创建数值列表
使用函数range()
使用range()创建数字列表
对数字列表执行简单的统计计算
列表解析
四、使用列表的一部分
切片
遍历切片
复制列表
五、元组
定义元组
遍历元组中的所有值
修改元组变量
六、设置代码格式
格式设置指南
缩进
行长
空行
其他格式设置指南
总结
在本章中,你将学习如何遍历整个列表,这只需要几行代码,无论列表有多长。循环让你能够对列表的每一个元素都采取一个或一系列相同的措施,从而高效地处理任何长度的列表,包括包含数千乃至数百万个元素的列表。
先看这个魔术师的例子:
❶ magicians = ['alice', 'david', 'carolina']
❷ for magician in magicians:
❸ print(magician)
首先,我们像第3章那样定义了一个列表(见❶)。接下来,我们定义了一个for 循环(见❷);这行代码让Python从列表magicians 中取出一个名字,并将其存储在变量magician 中。最后,我们让Python打印前面存储到变量magician 中的名字(见❸)。这样,对于列表中的每个名字,Python都将重复执行❷处和❸处的代码行。你可以这样解读这些代码:对于列表magicians 中的每位魔术师,都将其名字打印出来。
循环这种概念很重要,因为它是让计算机自动完成重复工作的常见方式之一。例如,在前面的magicians.py中使用的简单循环中,Python将首先读取其中的第一行代码:
for magician in magicians:
这行代码让Python获取列表magicians 中的第一个值('alice' ),并将其存储到变量magician 中。接下来,Python读取下一行代码:
print(magician)
它让Python打印magician 的值——依然是'alice' 。鉴于该列表还包含其他值,Python返回到循环的第一行:
for magician in magicians:
Python获取列表中的下一个名字——'david' ,并将其存储到变量magician 中,再执行下面这行代码:
print(magician)
Python再次打印变量magician 的值——当前为'david' 。接下来,Python再次执行整个循环,对列表中的最后一个值——'carolina' 进行处理。至此,列表中没有其他的值
了,因此Python接着执行程序的下一行代码。在这个示例中,for 循环后面没有其他的代码,因此程序就此结束。
刚开始使用循环时请牢记,对列表中的每个元素,都将执行循环指定的步骤,而不管列表包含多少个元素。如果列表包含一百万个元素,Python就重复执行指定的步骤一百万次,
且通常速度非常快。
另外,编写for 循环时,对于用于存储列表中每个值的临时变量,可指定任何名称。然而,选择描述单个列表元素的有意义的名称大有帮助。例如,对于小猫列表、小狗列表和
一般性列表,像下面这样编写for 循环的第一行代码是不错的选择:
for cat in cats:
for dog in dogs:
for item in list_of_items:
这些命名约定有助于你明白for 循环中将对每个元素执行的操作。使用单数和复数式名称,可帮助你判断代码段处理的是单个列表元素还是整个列表。
在for 循环中,可对每个元素执行任何操作。下面来扩展前面的示例,对于每位魔术师,都打印一条消息,指出他的表演太精彩了。
magicians = ['alice', 'david', 'carolina']
for magician in magicians:
print(magician.title() + ", that was a great trick!")
输出:
Alice, that was a great trick!
David, that was a great trick!
Carolina, that was a great trick!
该例子就是在循环的基础上使用了title()函数。
for 循环结束后再怎么做呢?通常,你需要提供总结性输出或接着执行程序必须完成的其他任务。在for 循环后面,没有缩进的代码都只执行一次,而不会重复执行。下面来打印一条向全体魔术师致谢的消息,感谢他们的精彩表演。想要在打印给各位魔术师的消息后面打印一条给全体魔术师的致谢消息,需要将相应的代码放在for 循环后面,且不缩进:
magicians = ['alice', 'david', 'carolina']
for magician in magicians:
print(magician.title() + ", that was a great trick!")
print("I can't wait to see your next trick, " + magician.title() + ".\n")
print("Thank you, everyone. That was a great magic show!")
Alice, that was a great trick!
I can't wait to see your next trick, Alice.David, that was a great trick!
I can't wait to see your next trick, David.Carolina, that was a great trick!
I can't wait to see your next trick, Carolina.Thank you, everyone. That was a great magic show!
使用for 循环处理数据是一种对数据集执行整体操作的不错的方式。
Python根据缩进来判断代码行与前一个代码行的关系。在前面的示例中,向各位魔术师显示消息的代码行是for 循环的一部分,因为它们缩进了。Python通过使用缩进让代码更易读;简单地说,它要求你使用缩进让代码整洁而结构清晰。在较长的Python程序中,你将看到缩进程度各不相同的代码块,这让你对程序的组织结构有大致的认识。 当你开始编写必须正确缩进的代码时,需要注意一些常见的缩进错误 。例如,有时候,程序员会将不需要缩进的代码块缩进,而对于必须缩进的代码块却忘了缩进。通过查看这样的错误示例,有助于你以后避开它们,以及在它们出现在程序中时进行修复。
对于位于for 语句后面且属于循环组成部分的代码行,一定要缩进。如果你忘记缩进,Python会提醒你:
magicians = ['alice', 'david', 'carolina']
for magician in magicians:
❶ print(magician)
print 语句(见❶)应缩进却没有缩进。Python没有找到期望缩进的代码块时,会让你知道哪行代码有问题。
File "magicians.py", line 3
print(magician)
^
IndentationError: expected an indented block
通常,将紧跟在for 语句后面的代码行缩进,可消除这种缩进错误。
有时候,循环能够运行而不会报告错误,但结果可能会出乎意料。试图在循环中执行多项任务,却忘记缩进其中的一些代码行时,就会出现这种情况。 例如,如果忘记缩进循环中的第2行代码(它告诉每位魔术师,我们期待他的下一次表演),就会出现这种情况:
magicians = ['alice', 'david', 'carolina']
for magician in magicians:
print(magician.title() + ", that was a great trick!")
❶ print("I can't wait to see your next trick, " + magician.title() + ".\n")
第二条print 语句(见❶)原本需要缩进,但Python发现for 语句后面有一行代码是缩进的,因此它没有报告错误。最终的结果是,对于列表中的每位魔术师,都执行了第一条print 语句,因为它缩进了;而第二条print 语句没有缩进,因此它只在循环结束后执行一次。由于变量magician 的终值为'carolina' ,因此只有她收到了消息“looking forward to the next trick”:
Alice, that was a great trick!
David, that was a great trick!
Carolina, that was a great trick!
I can't wait to see your next trick, Carolina.
这是一个逻辑错误 。从语法上看,这些Python代码是合法的,但由于存在逻辑错误,结果并不符合预期。如果你预期某项操作将针对每个列表元素都执行一次,但它却只执行了 一次,请确定是否需要将一行或多行代码缩进。
如果你不小心缩进了无需缩进的代码行,Python将指出这一点:
message = "Hello Python world!"
❶ print(message)
print 语句(见❶)无需缩进,因为它并不属于前一行代码,因此Python将指出这种错误:
File "hello_world.py", line 2
print(message)
^
IndentationError: unexpected indent
为避免意外缩进错误,请只缩进需要缩进的代码。在前面编写的程序中,只有要在for 循环中对每个元素执行的代码需要缩进。
如果你不小心缩进了应在循环结束后执行的代码,这些代码将针对每个列表元素重复执行。在有些情况下,这可能导致Python报告语法错误,但在大多数情况下,这只会导致逻辑错误。
例如,如果不小心缩进了感谢全体魔术师精彩表演的代码行,结果将如何呢?
magicians = ['alice', 'david', 'carolina']
for magician in magicians:
print(magician.title() + ", that was a great trick!")
print("I can't wait to see your next trick, " + magician.title() + ".\n")
❶ print("Thank you everyone, that was a great magic show!")
由于❶处的代码行被缩进,它将针对列表中的每位魔术师执行一次,如❷所示:
Alice, that was a great trick!
I can't wait to see your next trick, Alice.
❷ Thank you everyone, that was a great magic show!
David, that was a great trick!
I can't wait to see your next trick, David.
❷ Thank you everyone, that was a great magic show!
Carolina, that was a great trick!
I can't wait to see your next trick, Carolina.
❷ Thank you everyone, that was a great magic show!
这也是一个逻辑错误。Python不知道你的本意,只要代码符合语法,它就会运行。如果原本只应执行一次的操作执行了多次,请确定你是否不应该缩进执行该操作的代码。
for 语句末尾的冒号告诉Python,下一行是循环的第一行。
magicians = ['alice', 'david', 'carolina']
❶ for magician in magicians
print(magician)
如果你不小心遗漏了冒号,如❶所示,将导致语法错误,因为Python不知道你意欲何为。这种错误虽然易于消除,但并不那么容易发现。程序员为找出这样的单字符错误,花费的
时间多得令人惊讶。这样的错误之所以难以发现,是因为通常在我们的意料之外。
列表非常适合用于存储数字集合,而Python提供了很多工具,可帮助你高效地处理数字列表。明白如何有效地使用这些工具后,即便列表包含数百万个元素,你编写的代码也能运行得很好。
Python函数range() 让你能够轻松地生成一系列的数字。例如,可以像下面这样使用函数range() 来打印一系列的数字:
for value in range(1,5):
print(value)
在这个示例中,range() 只是打印数字1~4(包前不包后)。函数range() 让Python从你指定的第一个值开始数,并在到达你指定的第二个值 后停止,因此输出不包含第二个值(这里为5)。
要打印数字1~5,需要使用range(1,6) :
for value in range(1,6):
print(value)
使用range() 时,如果输出不符合预期,请尝试将指定的值加1或减1。
要创建数字列表,可使用函数list() 将range() 的结果直接转换为列表。如果将range() 作为list() 的参数,输出将为一个数字列表。
在前一节的示例中,我们打印了一系列数字。要将这些数字转换为一个列表,可使用list() :
numbers = list(range(1,6))
print(numbers)
结果如下:
[1, 2, 3, 4, 5]
使用函数range() 时,还可指定步长。例如,下面的代码打印1~10内的偶数:
even_numbers = list(range(2,11,2))
print(even_numbers)
在这个示例中,函数range() 从2开始数,然后不断地加2,直到达到或超过终值(11),因此输出如下:
[2, 4, 6, 8, 10]
使用函数range() 几乎能够创建任何需要的数字集。(思考一下乘方)
有几个专门用于处理数字列表的Python函数。例如,你可以轻松地找出数字列表的最大值、最小值和总和:
>>> digits = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
>>> min(digits)
0
>>> max(digits)
9
>>> sum(digits)
45
列表解析是将for 循环和创建新元素的代码合并成一行,并自动附加新元素。
你可以处理列表的部分元素——Python称之为切片。
要创建切片,可指定要使用的第一个元素和最后一个元素的索引。与函数range() 一样,Python在到达你指定的第二个索引前面的元素后停止。要输出列表中的前三个元素,需 要指定索引0~3,这将输出分别为0 、1 和2 的元素。
下面的示例处理的是一个运动队成员列表:
players = ['charles', 'martina', 'michael', 'florence', 'eli']
❶ print(players[0:3])
❶处的代码打印该列表的一个切片,其中只包含三名队员。输出也是一个列表,其中包含前三名队员:['charles', 'martina', 'michael']
你可以生成列表的任何子集,例如,如果你要提取列表的第2~4个元素,可将起始索引指定为1 ,并将终止索引指定为4 :
players = ['charles', 'martina', 'michael', 'florence', 'eli']
print(players[1:4])
这一次,切片始于'marita' ,终于'florence' :
['martina', 'michael', 'florence']
如果你没有指定第一个索引,Python将自动从列表开头开始:
players = ['charles', 'martina', 'michael', 'florence', 'eli']
print(players[:4])
由于没有指定起始索引,Python从列表开头开始提取:
['charles', 'martina', 'michael', 'florence']
要让切片终止于列表末尾,也可使用类似的语法。例如,如果要提取从第3个元素到列表末尾的所有元素,可将起始索引指定为2 ,并省略终止索引:
players = ['charles', 'martina', 'michael', 'florence', 'eli']
print(players[2:])
Python将返回从第3个元素到列表末尾的所有元素:
['michael', 'florence', 'eli']
无论列表多长,这种语法都能够让你输出从特定位置到列表末尾的所有元素。本书前面说过,负数索引返回离列表末尾相应距离的元素,因此你可以输出列表末尾的任何切片。
例如,如果你要输出名单上的最后三名队员,可使用切片players[-3:] :
players = ['charles', 'martina', 'michael', 'florence', 'eli']
print(players[-3:])
上述代码打印最后三名队员的名字,即便队员名单的长度发生变化,也依然如此。
如果要遍历列表的部分元素,可在for 循环中使用切片。在下面的示例中,我们遍历前三名队员,并打印他们的名字:
players = ['charles', 'martina', 'michael', 'florence', 'eli']
print("Here are the first three players on my team:")
❶ for player in players[:3]:
print(player.title())
❶处的代码没有遍历整个队员列表,而只遍历前三名队员:
Here are the first three players on my team:
Charles
Martina
Michael
在很多情况下,切片都很有用。例如,编写游戏时,你可以在玩家退出游戏时将其最终得分加入到一个列表中。然后,为获取该玩家的三个最高得分,你可以将该列表按降序排列,再创建一个只包含前三个得分的切片。处理数据时,可使用切片来进行批量处理;编写Web应用程序时,可使用切片来分页显示信息,并在每页显示数量合适的信息。
你经常需要根据既有列表创建全新的列表。下面来介绍复制列表的工作原理,以及复制列表可提供极大帮助的一种情形。 要复制列表,可创建一个包含整个列表的切片,方法是同时省略起始索引和终止索引([:] )。这让Python创建一个始于第一个元素,终止于最后一个元素的切片,即复制整个列表。
例如,假设有一个列表,其中包含你最喜欢的四种食品,而你还想创建另一个列表,在其中包含一位朋友喜欢的所有食品。不过,你喜欢的食品,这位朋友都喜欢,因此你可以通过复制来创建这个列表:
❶ my_foods = ['pizza', 'falafel', 'carrot cake']
❷ friend_foods = my_foods[:]
print("My favorite foods are:")
print(my_foods)
print("\nMy friend's favorite foods are:")
print(friend_foods)
我们首先创建了一个名为my_foods 的食品列表(见❶),然后创建了一个名为friend_foods 的新列表(见❷)。我们在不指定任何索引的情况下从列表my_foods 中提取
一个切片,从而创建了这个列表的副本,再将该副本存储到变量friend_foods 中。打印每个列表后,我们发现它们包含的食品相同:
My favorite foods are:
['pizza', 'falafel', 'carrot cake']
My friend's favorite foods are:
['pizza', 'falafel', 'carrot cake']
为核实我们确实有两个列表,下面在每个列表中都添加一种食品,并核实每个列表都记录了相应人员喜欢的食品:
my_foods = ['pizza', 'falafel', 'carrot cake']
❶ friend_foods = my_foods[:]
❷ my_foods.append('cannoli')
❸ friend_foods.append('ice cream')
print("My favorite foods are:")
print(my_foods)
print("\nMy friend's favorite foods are:")
print(friend_foods)
与前一个示例一样,我们首先将my_foods 的元素复制到新列表friend_foods 中(见❶)。接下来,在每个列表中都添加一种食品:在列表my_foods 中添加cannoli(见❷),而在friend_foods 中添加ice cream(见❸)。最后,打印这两个列表,核实这两种食品包含在正确的列表中。
My favorite foods are:
❹ ['pizza', 'falafel', 'carrot cake', 'cannoli']
My friend's favorite foods are:
❺ ['pizza', 'falafel', 'carrot cake', 'ice cream']
❹处的输出表明,'cannoli' 包含在你喜欢的食品列表中,而'ice cream' 没有。❺处的输出表明,ice cream包含在你朋友喜欢的食品列表中,而cannoli 没有。倘若我们只是简单地将my_foods 赋给friend_foods ,就不能得到两个列表。例如,下例演示了在不使用切片的情况下复制列表的情况:
my_foods = ['pizza', 'falafel', 'carrot cake']
#这行不通
❶ friend_foods = my_foods
my_foods.append('cannoli')
friend_foods.append('ice cream')
print("My favorite foods are:")
print(my_foods)
print("\nMy friend's favorite foods are:")
print(friend_foods)
这里将my_foods 赋给friend_foods ,而不是将my_foods 的副本存储到friend_foods (见❶)。这种语法实际上是让Python将新变量friend_foods 关联到包含 在my_foods 中的列表,因此这两个变量都指向同一个列表。鉴于此,当我们将cannoli 添加到my_foods 中时,它也将出现在friend_foods 中;同样,虽然ice cream好像只被加入到了friend_foods 中,但它也将出现在这两个列表中。 输出表明,两个列表是相同的,这并非我们想要的结果:
My favorite foods are:
['pizza', 'falafel', 'carrot cake', 'cannoli', 'ice cream']
My friend's favorite foods are:
['pizza', 'falafel', 'carrot cake', 'cannoli', 'ice cream']
列表非常适合用于存储在程序运行期间可能变化的数据集。列表是可以修改的,这对处理网站的用户列表或游戏中的角色列表至关重要。然而,有时候你需要创建一系列不可修改的元素,元组可以满足这种需求。Python将不能修改的值称为不可变的,而不可变的列表被称为元组。
元组看起来犹如列表,但使用圆括号而不是方括号来标识。定义元组后,就可以使用索引来访问其元素,就像访问列表元素一样。
例如,如果有一个大小不应改变的矩形,可将其长度和宽度存储在一个元组中,从而确保它们是不能修改的:
❶ dimensions = (200, 50)
❷ print(dimensions[0])
print(dimensions[1])
我们首先定义了元组dimensions (见❶),为此我们使用了圆括号而不是方括号。接下来,我们分别打印该元组的各个元素,使用的语法与访问列表元素时使用的语法相同(见❷):
200
50
下面来尝试修改元组dimensions 中的一个元素,看看结果如何:
dimensions = (200, 50)
❶ dimensions[0] = 250
❶处的代码试图修改第一个元素的值,导致Python返回类型错误消息。由于试图修改元组的操作是被禁止的,因此Python指出不能给元组的元素赋值:
Traceback (most recent call last):
File "dimensions.py", line 3, in <module>
dimensions[0] = 250
TypeError: 'tuple' object does not support item assignment
代码试图修改矩形的尺寸时,Python报告错误,这很好,因为这正是我们希望的。
像列表一样,也可以使用for 循环来遍历元组中的所有值:
dimensions = (200, 50)
for dimension in dimensions:
print(dimension)
就像遍历列表时一样,Python返回元组中所有的元素,:
200
50
虽然不能修改元组的元素,但可以给存储元组的变量赋值。因此,如果要修改前述矩形的尺寸,可重新定义整个元组:
❶ dimensions = (200, 50)
print("Original dimensions:")
for dimension in dimensions:
print(dimension)
❷ dimensions = (400, 100)
❸ print("\nModified dimensions:")
for dimension in dimensions:
print(dimension)
我们首先定义了一个元组,并将其存储的尺寸打印了出来(见❶);接下来,将一个新元组存储到变量dimensions 中(见❷);然后,打印新的尺寸(见❸)。这次,Python
不会报告任何错误,因为给元组变量赋值是合法的:
Original dimensions:200
50
Modified dimensions:
400
100
相比于列表,元组是更简单的数据结构。如果需要存储的一组值在程序的整个生命周期内都不变,可使用元组。
没什么好讲的
在本章中,你学习了:如何高效地处理列表中的元素;如何使用for 循环遍历列表,Python如何根据缩进来确定程序的结构以及如何避免一些常见的缩进错误;如何创建简单的数字列表,以及可对数字列表执行的一些操作;如何通过切片来使用列表的一部分和复制列表。你还学习了元组(它对不应变化的值提供了一定程度的保护),以及在代码变得越来越复杂时如何设置格式,使其易于阅读。