【写在前面】为进一步提高自己的python代码能力,打算把几本经典书籍重新过一遍,形成系统的知识体系,同时适当记录一些学习笔记,我尽量及时更新!先从经典的《Python编程:从入门到实战》书籍开始吧。有问题欢迎在评论区讨论,互相学习,good good study,day day up!上一篇文章《Python编程:从入门到实战》(第2版)学习笔记 第3章 列表简介介绍了如何创建和简单操作列表元素。在本章中,你将学习如何使用循环遍历整个列表,适用于任何长度的列表。
【特别说明】这是第二版的《Python编程:从入门到实战》,书本的Python版本是3.7.2,我自己运行代码的环境是3.7.0,不同Python版本的功能不同。
来源:《Python编程:从入门到实战》(第2版),侵权删!
4.1 遍历整个列表
当你需要对列表中的每个元素都执行相同的操作时,可使用for循环。
假设有一个魔术师名单,需要将其中每个魔术师的名字都打印出来。为此,我们可以分别获取名单中的每个名字,但如果名单很长,将包含大量重复的代码。每当名单的长度变化时,必须修改代码。下面使用for循环:
>>> magicians = ['alice', 'david', 'carolina'] #定义了一个列表
>>> for magician in magicians: #定义了一个for循环
>>> print(magician)
输出是列表中所有的姓名:
alice
david
carolina
4.1.1 深入地研究循环
循环是让计算机自动完成重复工作的常见方式之一。编写for循环时,用于存储列表中每个值的临时变量可指定任何名称。
4.1.2 在 for 循环中执行更多的操作
在for循环中,可对每个元素执行任何操作。对于每位魔术师,都打印一条消息,指出他的表演太精彩了。
>>> magicians = ['alice', 'david', 'carolina']
>>> for magician in magicians:
>>> print(f"{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!
在for循环中,想包含多少行代码都可以。在代码行for magician in magicians后面,每个缩进的代码行都是循环的一部分,且将针对列表中的每个值都执行一次。
下面告诉每位魔术师,我们期待他的下一次表演:
>>> magicians = ['alice', 'david', 'carolina']
>>> for magician in magicians:
>>> print(f"{magician.title()}, that was a great trick!")
>>> print(f"I can't wait to see your next trick, {magician.title()}.\n")
由于两条print语句都缩进了,因此它们都将针对列表中的每位魔术师执行一次。第二条print语句中的换行符"\n"在每次迭代结束后都插入一个空行,从而整洁地将针对各位魔术师的消息编组:
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.
4.1.3 在 for 循环结束后执行一些操作
for循环结束后再怎么做呢?在for循环后面,没有缩进的代码都只执行一次,而不会重复执行。下面打印一条向全体魔术师致谢的消息:
>>> magicians = ['alice', 'david', 'carolina']
>>> for magician in magicians:
>>> print(f"{magician.title()}, that was a great trick!")
>>> print(f"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循环处理数据是一种对数据集执行整体操作的不错的方式。
4.2 避免缩进错误
Python根据缩进来判断代码行与前一个代码行的关系。Python通过使用缩进让代码更易读;它要求你使用缩进让代码整洁而结构清晰。在较长的Python程序中,你将看到缩进程度各不相同的代码块,这让你对程序的组织结构有大致的认识。
当你开始编写必须正确缩进的代码时,需要注意一些常见的缩进错误。下面来看一些较为常见的缩进错误。
4.2.1 忘记缩进
对于位于for语句后面且属于循环组成部分的代码行,一定要缩进。如果你忘记缩进,Python会提醒你:
>>> magicians = ['alice', 'david', 'carolina']
>>> for magician in magicians:
>>> print(magician)
print语句没有缩进,报错:
File "magicians.py", line 3
print(magician)
^
IndentationError: expected an indented block
通常将紧跟在for语句后面的代码行缩进,可消除这种缩进错误。
4.2.2 忘记缩进额外的代码行
有时循环能够运行而不会报告错误,但结果可能会出乎意料。例如,如果忘记缩进循环中的第2行代码(它告诉每位魔术师,我们期待他的下一次表演),就会出现这种情况:
>>> magicians = ['alice', 'david', 'carolina']
>>> for magician in magicians:
>>> print(f"{magician.title()}, that was a great trick!")
>>> print(f"I can't wait to see your next trick, {magician.title()}.\n")
第二条print语句原本需要缩进,但Python发现for语句后面有一行代码是缩进的,因此它没有报告错误,但是第二条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.
这是一个逻辑错误。从语法上看,这些代码是合法的,但由于存在逻辑错误,因为你预期某项操作将针对每个列表元素都执行一次,但它却只执行了一次。
4.2.3 不必要的缩进
如果你不小心缩进了无需缩进的代码行,Python将报错:
>>> message = "Hello Python world!"
>>> print(message)
print语句无需缩进,因为它并不属于前一行代码:
File "hello_world.py", line 2
print(message)
^
IndentationError: unexpected indent
为避免意外缩进错误,请只缩进需要缩进的代码。
4.2.4 循环后不必要的缩进
如果你不小心缩进了应在循环结束后执行的代码,这些代码将针对每个列表元素重复执行。这可能导致语法错误或者逻辑错误。
例如,如果不小心缩进了感谢全体魔术师精彩表演的代码行,结果将如何呢?
>>> magicians = ['alice', 'david', 'carolina']
>>> for magician in magicians:
>>> print(f"{magician.title()}, that was a great trick!")
>>> print(f"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!
这也是一个逻辑错误。
4.2.5 遗漏了冒号
for语句末尾的冒号告诉Python,下一行是循环的第一行。
>>> magicians = ['alice', 'david', 'carolina']
>>> for magician in magicians
>>> print(magician)
如果你不小心遗漏了冒号,将导致语法错误。这种错误虽然易于消除,但并不那么容易发现!
4.3 创建数值列表
需要存储一组数字的原因有很多,例如,在游戏中,需要跟踪每个角色的位置。在数据可视化中,处理的几乎都是由数字(如温度、距离、人口数量、经度和纬度等)组成的集合。
列表非常适合用于存储数字集合,而Python提供了很多工具高效地处理数字列表,同样适用于百万个元素的列表。
4.3.1 使用函数 range()
Python函数range()能够生成一系列的数字。
>>> for value in range(1,5):
>>> print(value)
上述代码它不会打印数字5:
1
2
3
4
函数range()从你指定的第一个值开始数,并在到达你指定的第二个值后停止,因此输出不包含第二个值(这里为5)。要打印数字1~5,需要使用range(1,6):
>>> for value in range(1,6):
>>> print(value)
输出从1开始,到5结束:
1
2
3
4
5
使用range()时,如果输出不符合预期,请尝试将指定的值加1或减1。
4.3.2 使用 range()创建数字列表
要创建数字列表,可使用函数list()将range()的结果直接转换为列表。
>>> numbers = list(range(1,6))
>>> print(numbers)
结果如下:
[1, 2, 3, 4, 5]
函数range()可指定步长。
>>> even_numbers = list(range(2,11,2)) #打印1~10内的偶数
>>> print(even_numbers)
函数range()从2开始数,然后不断地加2,直到达到或超过终值(11),输出如下:
[2, 4, 6, 8, 10]
使用函数range()几乎能够创建任何需要的数字集。例如,创建包含前10个整数(即1~10)的平方的一个列表?在Python中,两个星号(**)表示乘方运算。
>>> squares = [] #创建了一个空列表
>>> for value in range(1,11):
>>> square = value**2 #计算当前值的平方
>>> squares.append(square) #变量square附加到列表squares末尾
>>> print(squares) #打印
结果如下:
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
代码的简洁写法:
>>> squares = []
>>> for value in range(1,11):
>>> squares.append(value**2)
创建更复杂的列表时,可使用上述两种方法中的任何一种。
4.3.3 对数字列表执行简单的统计计算
介绍用于处理数字列表的Python函数。例如,数字列表的最大值、最小值和总和:
>>> digits = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
>>> min(digits)
0
>>> max(digits)
9
>>> sum(digits)
45
注意 这里介绍的知识也适用于包含数百万个数字的列表。
4.3.4 列表解析
前面介绍的生成列表squares的方式包含三四行代码,而列表解析只需一行代码。列表解析将for循环和创建新元素的代码合并成一行,并自动附加新元素。
>>> squares = [value**2 for value in range(1,11)]
>>> print(squares)
- 首先指定一个列表名,如squares;
- 然后指定一个左方括号,并定义一个表达式,用于生成你要存储到列表中的值。这里表达式为value**2,它计算平方值;
- 接下来,编写一个for循环,用于给表达式提供值,再加上右方括号。
在这个示例中,for循环为for value in range(1,11),它将值1~10提供给表达式value**2。注意这里的for语句末尾没有冒号。
结果:[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
4.4 使用列表的一部分
在第3章中介绍了如何访问单个列表元素。这里将学习如何处理列表的所有元素——切片。
4.4.1 切片
要创建切片,可指定要使用的第一个元素和最后一个元素的索引。与函数range()一样,切片在到达你指定的第二个索引前面的元素后停止。
>>> 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])
输出:
['martina', 'michael', 'florence']
如果没有指定第一个索引,将自动从列表开头开始:
>>> players = ['charles', 'martina', 'michael', 'florence', 'eli']
>>> print(players[:4])
输出:
['charles', 'martina', 'michael', 'florence']
列表末尾类似。例如,提取从第3个元素到列表末尾的所有元素,可将起始索引指定为2,并省略终止索引:
>>> players = ['charles', 'martina', 'michael', 'florence', 'eli']
>>> print(players[2:])
输出:
['michael', 'florence', 'eli']
无论列表多长,这种语法都能够让你输出从特定位置到列表末尾的所有元素。当然,也可以使用负数索引。例如,输出名单上的最后三名队员:
>>> players = ['charles', 'martina', 'michael', 'florence', 'eli']
>>> print(players[-3:]) #输出['michael', 'florence', 'eli']
4.4.2 遍历切片
如果要遍历列表的部分元素,可在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应用程序时,可使用切片来分页显示信息,并在每页显示数量合适的信息。
4.4.3 复制列表
你经常需要复制列表,可通过创建一个包含整个列表的切片,方法是同时省略起始索引和终止索引([:])。
例如,有一个列表包含你最喜欢的食品,而你还想创建另一个列表包含一位朋友喜欢的所有食品。不过,你喜欢的食品,这位朋友都喜欢,因此你可以通过复制来创建这个列表:
>>> my_foods = ['pizza', 'falafel', 'carrot cake'] #创建一个名为my_foods的食品列表
>>> friend_foods = my_foods[:] #创建一个名为friend_foods的新列表
>>> print("My favorite foods are:")
>>> print(my_foods)
>>> print("\nMy friend's favorite foods are:")
打印每个列表后,发现它们包含的元素相同:
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') #在列表my_foods中添加'cannoli'
>>> friend_foods.append('ice cream') #在friend_foods中添加'ice cream'
>>> print("My favorite foods are:")
>>> print(my_foods)
>>> print("\nMy friend's favorite foods are:")
>>> print(friend_foods)
打印这两个列表,核实这两种食品包含在正确的列表中。
My favorite foods are:
['pizza', 'falafel', 'carrot cake', 'cannoli']
My friend's favorite foods are:
['pizza', 'falafel', 'carrot cake', 'ice cream']
倘若我们只是简单地将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。这种语法实际上是将新变量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']
4.5 元组
列表非常适合用于存储在程序运行期间可能变化的数据集,因为列表是可以修改的。然而,有时候你需要创建不可修改的元素。Python将不能修改的值称为不可变的,而不可变的列表被称为元组。
4.5.1 定义元组
元组使用圆括号而不是方括号来标识。定义元组后,可以使用索引来访问其元素,就像访问列表元素一样。例如,如果有一个大小不应改变的矩形,可将其长度和宽度存储在一个元组中,从而确保它们是不能修改的:
>>> dimensions = (200, 50) #定义元组dimensions
>>> print(dimensions[0]) #分别打印该元组的各个元素
>>> print(dimensions[1])
输出结果:
200
50
下面来尝试修改元组dimensions中的一个元素,看看结果如何:
>>> dimensions[0] = 250
由于试图修改元组的操作是被禁止的,因此报错:
Traceback (most recent call last):
File "dimensions.py", line 2, in <module>
dimensions[0] = 250
TypeError: 'tuple' object does not support item assignment
注意 要定义只包含一个元素的元组,必须在这个元素后面加上逗号,如my_tuple = (3,)。
4.5.2 遍历元组中的所有值
像列表一样,也可以使用for循环来遍历元组中的所有值:
>>> dimensions = (200, 50)
>>> for dimension in dimensions:
>>> print(dimension)
就像遍历列表时一样,Python返回元组中所有的元素:
200
50
4.5.3 修改元组变量
虽然不能修改元组的元素,但可以给存储元组的变量赋值。因此,如果要修改前述矩形的尺寸,可重新定义整个元组:
>>> dimensions = (200, 50)
>>> print("Original dimensions:")
>>> for dimension in dimensions:
>>> print(dimension)
>>> dimensions = (400, 100) #将一个新元组存储到变量dimensions中
>>> print("\nModified dimensions:")
>>> for dimension in dimensions:
>>> print(dimension)
这次不会报错,因为给元组变量赋值是合法的:
Original dimensions:
200
50
Modified dimensions:
400
100
相比于列表,元组是更简单的数据结构。如果需要存储的一组值在程序的整个生命周期内都不变,可使用元组。
4.6 设置代码格式
随着你编写的程序越来越长,有必要了解一些代码格式设置约定。为确保所有人编写的代码的结构都大致一致,Python程序员都遵循一些格式设置约定。要成为专业程序员,应从现在开始就遵循这些指南,以养成良好的习惯。
4.6.1 格式设置指南
若要提出Python语言修改建议,需要编写Python改进提案(Python Enhancement Proposal, PEP)。PEP 8是最古老的PEP之一,它向Python程序员提供了代码格式设置指南。
Python格式设置指南的编写者深知,代码被阅读的次数比编写的次数多。代码编写出来后,调试时你需要阅读它;给程序添加新功能时,需要花很长的时间阅读代码;与其他程序员分享代码时,这些程序员也将阅读它们。
如果一定要在让代码易于编写和易于阅读之间做出选择,Python程序员几乎总是会选择后者。下面的指南可帮助你从一开始就编写出清晰的代码。
4.6.2 缩进
PEP 8建议每级缩进都使用四个空格,这既可提高可读性,又留下了足够的多级缩进空间。
在字处理文档中,大家常常使用制表符而不是空格来缩进。对于字处理文档来说,这样做的效果很好,但混合使用制表符和空格会让Python解释器感到迷惑。每款文本编辑器都提供了一种设置,可将输入的制表符转换为指定数量的空格。你在编写代码时应该使用制表符键,但一定要对编辑器进行设置,使其在文档中插入空格而不是制表符。
在程序中混合使用制表符和空格可能导致极难解决的问题。如果你混合使用了制表符和空格,可将文件中所有的制表符转换为空格,大多数编辑器都提供了这样的功能。
4.6.3 行长
很多Python程序员都建议每行不超过80字符。最初制定这样的指南时,在大多数计算机中,终端窗口每行只能容纳79字符;当前,计算机屏幕每行可容纳的字符数多得多,为何还要使用79字符的标准行长呢?专业程序员通常会在同一个屏幕上打开多个文件,使用标准行长可以让他们在屏幕上并排打开两三个文件时能同时看到各个文件的完整行。PEP 8还建议注释的行长都不超过72字符,因为有些工具为大型项目自动生成文档时,会在每行注释开头添加格式化字符。
PEP 8中有关行长的指南并非不可逾越的红线,有些小组将最大行长设置为99字符。在学习期间,你不用过多地考虑代码的行长,但别忘了,协作编写程序时,大家几乎都遵守PEP 8指南。在大多数编辑器中,都可设置一个视觉标志——通常是一条竖线(不能越过的界线)。
4.6.4 空行
使用空行将程序的不同部分分开。你应该使用空行来组织程序文件,但也不能滥用;只要按本书的示例展示的那样做,就能掌握其中的平衡。例如,如果你有5行创建列表的代码,还有3行处理该列表的代码,那么用一个空行将这两部分隔开是合适的。然而,你不应使用三四个空行将它们隔开。
空行不会影响代码的运行,但会影响代码的可读性。Python解释器根据水平缩进情况来解读代码,但不关心垂直间距。
4.6.5 其他格式设置指南
PEP 8还有很多其他的格式设置建议,但这些指南针对的程序大都比目前为止本书提到的程序复杂。等介绍更复杂的Python结构时,我们再来分享相关的PEP 8指南。
4.7 小结
本章学习了如何高效地处理列表中的元素;如何使用for循环遍历列表;如何创建简单的数字列表以及可对数字列表执行的一些操作;如何通过切片来使用列表的一部分和复制列表。你还学习了元组(它对不应变化的值提供了一定程度的保护),以及在代码变得越来越复杂时如何设置格式,使其易于阅读。
说明:记录学习笔记,如果错误欢迎指正!写文章不易,转载请联系我。