时隔数日,随着我科目二的失败,需要等待十天才能继续约考。所以本栏目继续更新~
4 操作列表
4.1 遍历整个列表
你经常需要遍历列表的所有元素,对每个元素执行相同的操作。例如,在网站中,可能需要显示文章列表中的每个标题。需要对列表中的每个元素都执行相同操作时,可使用python中的for循环。
假设我需要将我女友的名单上的名字每个都打印出来。为此,可以分别获取名单上的每个名字,但这种做法会导致出现很多问题。例如,如果名单很长,将包含大量重复的代码。另外,每当名单长度发生变化是,都必须修改代码。通过for循环,可以让Python去处理这些问题。
下面使用for循环来打印魔术师名单中的所有名字:
>>> mygirlfriends = ['全孝盛','朴孝敏','朴智妍']
>>> for mywife in mygirlfriends:
... print(mywife)
...
全孝盛
朴孝敏
朴智妍
这里需要注意一下,如果是用mac终端进行编程的话,需要特别注意段首的空格。不要以为出现了…就不需要加空格了。
首先像第3章那样定义一个列表。接下来,定义一个for循环。这行代码让Python从列表的mygirlfriends中取一个名字,并将其与变量mywife相关联。最后,让Python打印前面赋给变量mywife的名字。这样列表的每个名字,Python都将重复执行循环内的代码行。
循环,是我学Python至今唯二感到复杂的东西。还有一个复杂的叫嵌套。当循环与嵌套交相呼应,互为表里的时候,简直看的头大。所以如果这块不是很看得懂的话也很正常。需要配合视频多练。
4.1.1 深入研究循环
循环这种概念很重要,因为它是让计算机自动完成重复工作的常见方法之一。例如,在上面使用的简单循环里,Python将首先读取其中的第一行代码:
for mywife in mygirlfriends:
这行代码让Python获取列表mygirlfriends中第一个值“全孝盛”,并将其与变量mywife相关联。
接下来,Python读取下一行代码:
print(mywife)
它让Python打印mywife的值,依然是“全孝盛”。
鉴于该列表还包含其他值,Python返回到循环的第一行:
for mywife in mygirlfriends:
Python获取列表的下一个名字:“朴孝敏”,并将其与变量mywife相关联。
再执行下面这行代码:
print(mywife)
Python再次打印变量mywife的值,当前为“朴孝敏”。
接下来Python再次执行整个循环。对列表的最后一个值“朴智妍”进行处理。至此,列表中没有其他值了。因此将执行程序的下一行代码。在这个示例中,for循环后面没有任何代码,因此程序结束。
刚开始使用循环时请牢记,对列表中的每个元素,都将执行循环制定的步骤,而不管列表包含多少个元素。如果列表包含一百万个元素,Python就重复执行制定的步骤一百万次,且通常速度非常快。
另外编写for循环时,可以一次与列表中的每个值相关联的临时变量指定任意名称。然而选择描述单个列表元素的有意义名称大有裨益。例如,对于小猫列表、小狗列表和一般性列表,像下面这样编写for循环的第一行代码是不错的选择:
for cat in cats:
for dog in dogs:
for item in list_of_items:
这些命名约定有助于你明白for循环中将对每个元素执行的操作。使用单数和复数式名称,可帮助你判断代码处理的是单个列表元素还是整个列表。
虽然我尽量在示例中使用中文命名,但其实编程还是英语的世界。尽量使用标准英语,有助于未来在工作中显得更专业,更不容易出错。
一般来说,拼音就是很low的方式命名方式。比拼音更low的是拼音的首字母缩写。千万千万不要做这么蠢的事情,答应我,哪怕不懂英文,用拼音也要用全称,不要用首字母缩写,真的是看不懂。
4.1.2 在for循环中执行更多操作
在for循环中,可对每个元素执行任何操作。下面来扩展前面的示例,对于每位女朋友,都打印一条消息,指出她真的太漂亮了。
>>> mygirlfriends = ['全孝盛','朴孝敏','朴智妍']
>>> for mywife in mygirlfriends:
... print(f"{mywife},你真的好漂亮啊~")
...
全孝盛,你真的好漂亮啊~
朴孝敏,你真的好漂亮啊~
朴智妍,你真的好漂亮啊~
相比于前一个示例,唯一的不同是为每位女朋友打印了一条以其名字为抬头的消息。这个循环第一次迭代时,变量mywife的值为“全孝盛”。因此Python打印的第一条消息的抬头为“全孝盛”;第二次是“朴孝敏”;第三次迭代是“朴智妍”。
在for循环中,想包含多少行代码都可以。在代码行for mywife in mygirlfriends后面,每个缩进代码行都是循环的一部分。将针对列表中的每个值都执行一遍。因此可对列表中的每个值执行任意次数的操作。
下面再添加一行代码,告诉每位女友,期待她们下次穿着汉服来:
>>> mygirlfriends = ['全孝盛','朴孝敏','朴智妍']
>>> for mywife in mygirlfriends:
... print(f"{mywife},你真的好漂亮啊~")
... print(f"下次穿着汉服来我家吧,{mywife}\n.")
...
全孝盛,你真的好漂亮啊~
下次穿着汉服来我家吧,全孝盛
.
朴孝敏,你真的好漂亮啊~
下次穿着汉服来我家吧,朴孝敏
.
朴智妍,你真的好漂亮啊~
下次穿着汉服来我家吧,朴智妍
两个函数都调用了print()都锁紧了,因此它们都将针对列表中的每位女友执行一次。第二个函数调用print()中的换行符“\n”在每次迭代结束后都加入一个空行,从而整洁地将针对每位女友的消息编组。
在for循环中,想包含多少行代码都可以。十几种,你会发现使用for循环对每个元素执行众多不同的操作很有用。
4.1.3 在for循环结束后执行一些操作
for循环结束后怎么办呢?通常你需要提供总结性输出或接着执行程序必须完成的其他任务。
在for循环后面,没有锁紧的代码都只执行一次,不会重复执行。下面打印一条向全体女友表白的消息。想要在打印给各位女友的消息后面打印一条给全体女友表白的消息,需要将相应的代码放在for循环后面,且不缩进:
mygirlfriends = ['全孝盛','朴孝敏','朴智妍']
for mywife in mygirlfriends:
print(f"{mywife},你真的好漂亮啊~")
print(f"下次穿着汉服来我家吧,{mywife}\n.")
print("各位女友~我爱你们~")
你在前面看到了,开头两个函数调用print()针对列表中的每位女友重复执行。然而,第三个函数调用print()没有锁紧,因此只执行一次:
全孝盛,你真的好漂亮啊~
下次穿着汉服来我家吧,全孝盛
.
朴孝敏,你真的好漂亮啊~
下次穿着汉服来我家吧,朴孝敏
.
朴智妍,你真的好漂亮啊~
下次穿着汉服来我家吧,朴智妍
.
各位女友~我爱你们~
使用for循环处理数据是一种对数据集执行整体操作的不错方式。例如,你可能使用for循环来初始化游戏:遍历角色列表,将每个橘色显示到屏幕上。然后在循环后面添加一个不缩进的代码块,在屏幕中绘制所有角色后显示一个“开始游戏”的按钮。
4.2 避免缩进错误
Python根据缩进来判断代码行与前一个代码行的关系。在前面的示例中,向各位女友显示消息的代码行是for循环的一部分,因为它们缩进了。Python通过使用缩进让代码更易读。简单地说,它要求你使用缩进让代码整洁且结构清晰。在较长的Python程序中,你将看到缩进程度各不相同的代码块,从而对代码的组织结构有大致认识。
开始编写必须正确缩进的代码时,需要注意一些常见的缩进错误。例如程序员有时候会将不需要缩进的代码块缩进,而对于必须缩进的代码块却忘了缩进。查看这样的错误示例有助于你以后避开他们,以及在它们出现在程序中时进行修复。
鉴于这部分内容比较繁复,所以我将省略部分我觉得比较重复且麻烦的内容。
4.2.1 忘记缩进
>>> mygirlfriends = ['全孝盛','朴孝敏','朴智妍']
>>> for mywife in mygirlfriends:
print(f"{mywife},你真的好漂亮啊~")
结果是报错:
print(f"{mywife},你真的好漂亮啊~")
^
IndentationError: expected an indented block
4.2.2 忘记缩进额外的代码行
mygirlfriends = ['全孝盛','朴孝敏','朴智妍']
for mywife in mygirlfriends:
print(f"{mywife},你真的好漂亮啊~")
print(f"下次穿着汉服来我家吧,{mywife}\n.")
结果是不报错,但是不匹配需求原意,出现逻辑错误:
全孝盛,你真的好漂亮啊~
朴孝敏,你真的好漂亮啊~
朴智妍,你真的好漂亮啊~
下次穿着汉服来我家吧,朴智妍
4.2.3 不必要的缩进
mygirlfriends = ['全孝盛','朴孝敏','朴智妍']
print(mygirlfriends)
结果是报错:
print(mygirlfriends)
IndentationError: unexpected indent
4.2.4 循环后不必要的缩进
mygirlfriends = ['全孝盛','朴孝敏','朴智妍']
for mywife in mygirlfriends:
print(f"{mywife},你真的好漂亮啊~")
print(f"下次穿着汉服来我家吧,{mywife}\n.")
print("各位女友~我爱你们~")
结果是不报错,但是不匹配需求原意,出现逻辑错误:
全孝盛,你真的好漂亮啊~
下次穿着汉服来我家吧,全孝盛
.
各位女友~我爱你们~
朴孝敏,你真的好漂亮啊~
下次穿着汉服来我家吧,朴孝敏
.
各位女友~我爱你们~
朴智妍,你真的好漂亮啊~
下次穿着汉服来我家吧,朴智妍
.
各位女友~我爱你们~
4.2.5 遗漏了冒号
for语句末尾的冒号告诉Python,下一行是循环的第一行。如果不小心遗漏了冒号,将会导致语法错误,因为python不知道你意欲何为。这种错误虽然易于消除,但并不那么容易发现。程序员为找出这样的单字符错误,花费的时间多得令人惊讶。此类错误之所以难以发现,是因为通常在人们的医疗之外。
越简单的地方越容易出错,也越难找。因为没人想到是这个原因,不只是冒号。因为中英文标点符号在某些编辑器里看着基本一样,所以中英文标点符号的错输往往是最容易犯错的地方。比如中文的(,)和英文的(,)。中文的(。)和英文的(.)。
好在现在很多编辑器都有自我纠错的功能,能将中英文符号进行纠错,显示哪里有问题。这显然是方便很多了。
说到这个越简单的地方就越容易出错,我就想说说我的科目二考试,我前面都满分过的,但是最后一个科目的时候……
咳咳咳,我们继续学习。
4.3 创建数值列表
需要存储一组数的原因有很多。例如,在游戏中,需要跟踪每个角色的位置,还可能需要跟踪玩家的几个最高得分;在数据可视化中,处理的几乎是由数(如温度、距离、人口等)组成的集合。
列表非常适合用于存储数字集合,而Python提供了很多工具,可帮助你高效地处理数字列表。明白如何有效地使用这些工具后,即便列表包含数百万个元素,你编写的代码也能运行得很好。
4.3.1 使用函数range()
python函数range()让你能够轻松地生成一系列数。例如,可以像下面这样使用函数range()来打印一系列数:
>>> for mygirlfriend in range(1,5):
... print(mygirlfriend)
...
1
2
3
4
上述代码好像应该打印数1 ~ 5,但实际上不会打印5.这是变成语言中常见的差一行为的结果。函数range()让Python从指定的第一个值开始数,并在到达你制定的第二个值时停止。因为它在第二个值出停止,所以输出不包含该值(这里为5)。
调用函数range()时,也可只制定一个参数,这样它将从0开始。例如,range(6)返回数0 ~ 5.
4.3.2 使用range()创建数字列表
要创建数字列表,可使用函数list()将range()的结果直接转换为列表。如果将range()作为list()的参数,输出将是一个数字列表。
在前一节的实例中,只是将一系列数打印出来。要将这组数转化为列表,可使用list():
>>> numbers = list(range(1,6))
>>> print(numbers)
[1, 2, 3, 4, 5]
使用函数range()时,还可指定步长。为此,可给这个函数指定第三个参数,Python将根据这个步长来生成数。例如我们可以将上述的示例进行修改,输出的内容将全部为奇数:
>>> numbers = list(range(1,6,2))
>>> print(numbers)
[1, 3, 5]
在这个示例中,函数range()从1开始数,然后不断加2,直到达到或超过终值(6)。
使用函数range()几乎能够创建任何需要的数集。例如,如何创建一个列表,其中包含前10个整数的平方呢?在Python中,用两个星号**表示乘方运算。下面的代码演示了如何将前10个整数加入一个列表中:
sqauares = []
for value in range(1,11):
pingfang = value ** 2
sqauares.append(pingfang)
print(sqauares)
首先,创建一个名为squares的空列表。接下来使用函数range()让Python遍历1 ~ 10的值。在循环中,计算当前值的平方。并将结果赋给变量pingfang。然后将新计算得到的平方值附加到列表squares末尾。最后,循环结束后,打印列表squares:
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
为了让代码更简洁,可不适用临时变量pingfang,而直接将每个计算得到的值附加到列表末尾。
sqauares = []
for value in range(1,11):
squares.append(value**2)
print(squares)
创建更复杂的列表时,可使用上述两种方法中的任何一种。有时候,使用临时变量会让代码更易读;而在其他情况下,这样做只会让代码无畏地变长。你首先应该考虑的是,编写清晰易懂且能完成所需功能的代码,等到审核代码时,在考虑使用更高效的方法。
这个部分,之前在小甲鱼的教程里也有说过,优先保证完成,至于高不高效,后面再说吧。事有轻重缓急,用高效的方式装大神显然没有完成任务重要。
4.3.3 对数字列表执行简单的统计计数
有几个专门对于处理数字列表的Python函数。例如,你可以轻松地找出数字列表的最大值、最小值和总和:
>>> digits = [1,2,3,4,5,6,7,8,9,10]
>>> min(digits)
1
>>> max(digits)
10
>>> sum(digits)
55
4.3.4 列表解析
前面介绍的生成列表squares的方式包含三四行代码,而列表解析让你只需编写一行代码就能生成这样的列表。列表解析将for循环和创建新元素的代码合并成一行,并自动附加新元素。面向初学者的书并非都会介绍列表解析,这里之所以介绍列表解析,是因为等你开始阅读他人编写的代码时,很可能会遇到他。
下面的示例使用的列表解析构建你在前面看到的平方数列表:
square = [value**2 for value in range(1,11)]
print(square)
要使用这种语法,首先要制定一个描述性的列表名,如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张中,你学习了如何访问单个列表元素。在本章中,你一直在学习如何处理列表的所有元素。你还可以处理列表的部分元素,Python称之为切片。
4.4.1 切片
要创建切片,可指定要使用的第一个元素和最后一个元素索引。与函数range()一样,Python在到达第二个索引之前的元素后停止。要输出列表中的前三个元素,需要指定索引0和3,这将返回索引0、1和2的元素。
>>> mygirlfriend = ['全孝盛','金泫雅','朴草娥','朴孝敏','朴智妍']
>>> print(mygirlfriend[0:3])
['全孝盛', '金泫雅', '朴草娥']
上述的代码打印该列表的一个切片,其中只包含三个女友。输出也是一个列表,其中博涵前三个女友。
你可以生成列表的任意子集。例如,如果要提取列表的第二、第三和第四个元素,可将起始索引指定为1,并将终止索引指定为4.
>>> mygirlfriend = ['全孝盛','金泫雅','朴草娥','朴孝敏','朴智妍']
>>> print(mygirlfriend[1:4])
['金泫雅', '朴草娥', '朴孝敏']
此时,切片始于'金泫雅'、终于'朴孝敏'。
如果没有指定第一个索引,Python将自动从列表开头开始:
>>> mygirlfriend = ['全孝盛','金泫雅','朴草娥','朴孝敏','朴智妍']
>>> print(mygirlfriend[:4])
['全孝盛', '金泫雅', '朴草娥', '朴孝敏']
由于没有指定起始索引,Python从列表开始开始提取。
要让切片终止于列表末位,也可使用类似的语法。例如,如果要提取从第三个元素到列表末位的所有元素,可将起始索引指定为2,并省略终止索引:
>>> mygirlfriend = ['全孝盛','金泫雅','朴草娥','朴孝敏','朴智妍']
>>> print(mygirlfriend[2:])
['朴草娥', '朴孝敏', '朴智妍']
无论列表多长,这种语法都能够让你输出从特定位置到列表末位的所有元素。上一章说过,负数索引返回离列表末位相应距离的元素,因此你可以输出列表末位的任意切片。例如,如果要输出名单上的最后三名女友,可使用切片mygirlfriend[-3:]:
>>> mygirlfriend = ['全孝盛','金泫雅','朴草娥','朴孝敏','朴智妍']
>>> mygirlfriend[-3:]
['朴草娥', '朴孝敏', '朴智妍']
注意:可在表示切片的方括号内指定第三个值(步进)。这个值告诉Python在制定范围内每隔多少元素提取一个。
4.4.2 遍历切片
如果要遍历列表的部分元素,可在for循环中使用切片。下面的示例遍历前两名女友,并打印她们的名字:
>>> mygirlfriend = ['朴孝敏','朴智妍','全孝盛','金泫雅','朴草娥',]
>>> print("身高超过一米六五的人是:")
身高超过一米五的人是:
>>> print(mygirlfriend[:2])
['朴孝敏', '朴智妍']
此处的代码没有遍历整个队员列表,而只遍历前三名女友。
在很多情况下,切片都很有用。例如,编写游戏时,你可以在玩家推出游戏时将其最终得分加入一个列表中,然后将该列表按降序排列以获取三个最高得分。再创建一个只包含前三个得分的切片;处理数据时,可使用切片来进行批量处理;编写web应用程序时,可使用切片来分页显示信息,并在每页显示数量合适的信息。
4.4.3 复制列表
我们经常需要根据既有列表创建新泉的列表。下面来介绍复制列表的工作原理,以及复制列表可提供极大帮助的一种情形。
要赋值列表,可创建一个包含整个列表的切片,方法是同时省略起始索引和终止索引([:]).这让Python创建一个始于第一个元素、终止于最后一个元素的切片,即整个列表的副本。
>>> mygirlfriend = ['朴孝敏','朴智妍','全孝盛','金泫雅','朴草娥']
>>> mywife = mygirlfriend[:]
>>> print(f"我的女朋友们是{mygirlfriend}")
我的女朋友们是['朴孝敏', '朴智妍', '全孝盛', '金泫雅', '朴草娥']
>>> print(f"我的娘子们是{mywife}")
我的娘子们是['朴孝敏', '朴智妍', '全孝盛', '金泫雅', '朴草娥']
这里需要注意的是,当使用切片的手法,让B复制了A列表后,A列表的增减与否与B列表无关。B列表是单独的一个列表。如果不使用切片法,而直接mywife = mygirlfriend,这相当于一种映射。这涉及到浅拷贝和深拷贝,可以看我之前的笔记。
4.5 元组
列表非常适合用于存储程序运行期间可能变化的数据集。列表是可以修改的,这对处理网站的用户列表或游戏中的角色列表至关重要。然而,有时候你需要创建一系列不可修改的元素,元组可以满足这种需求。Python将不可能修改的值称为不可变的,而不可变的列表被称为元组。
4.5.1 定义元组
元组看起来很像列表,但是用圆括号而非中括号来标识。定义元组后,就可以是用索引来访问其元素,就像访问列表元素一样。
例如,如果有一个大小不应改变的矩形,可将其长度和宽度存储在一个元组中,从而确保它们是不能修改的:
>>> juxing = (30,10)
>>> print(juxing[1])
10
>>> print(juxing[0])
30
下面我们尝试修改元组矩形的一个元素,看结果如何:
>>> juxing[1]=555
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
此处的代码试图修改第第二个元素的值,导致Python返回类型错误消息。由于试图修改元组的操作是被禁止的,因此Python指出不能给元组的元素赋值。
注意:严格地说,元组是由逗号标识的,圆括号只是让元组看起来更整洁、更清晰。如果你要定义只包含一个元素的元组,必须在这个元素后面加上逗号:
tt = (1,)
创建只包含一个元素的元组通常没有意义,但自动生成的元组有可能只有一个元素。
4.5.2 遍历元组中的所有值
像列表一样,也可以使用for循环来遍历元组中的所有值:
mygirlfriends = ('朴孝敏','朴智妍','全孝盛','金泫雅','朴草娥')
for mygirlfriend in mygirlfriends:
print(mygirlfriend)
就像遍历列表时一样,Python返回元组中的元素。
4.5.3 修改元组变量
虽然不能修改元组的元素,但可以给存储元组的变量赋值。
>>> mygirlfriends = ('朴孝敏','朴智妍','全孝盛','金泫雅','朴草娥')
>>> mygirlfriends = ('金珍熙')
>>> print(mygirlfriends)
金珍熙
首先定义一个元组,并将其存储的值打印出来。接下来,将一个新元组关联到变量mygirlfriend。然后,打印新的值。这次Python不会引发任何错误,因为给元组变量重新赋值是合法的。
相比于列表,元组是更简单的数据结构。如果需要存储的一组值在程序的整个生命周期内部不变,就可以使用元组。
4.6 设置代码格式
这部分内容也比较繁复,我将挑选其中值得注意的内容记录,并不会全盘记录(相信影响也不会很大)。
为确保所有人编写的代码结构大致一致,Python程序员会遵循一些格式设置约定。学会编写整洁的Python后,就能明白他人编写的Python代码的整体结构——只要他们和你遵循相同的指南。要成为专业程序员,应从现在开始遵循这些指南,以养成良好的习惯。
4.6.2 缩进
PEP8(Python改进提案)建议每级缩进都是用四个空格。在字处理文档中,大家常常使用制表符(胭惜雨:也就是TAB啦)而不是空格来缩进。如果混合是用了制表符和空格,可将文件中的所有制表符都转换为空格,大多数编辑器提供了这样的功能。
其实我不是很能理解为啥要用四个空格,制表符一个就够了。从效率的角度上来讲,按四次空格的效率肯定没有按一次tab效率高呀。
但这个东西嘛,怎么说也是人家制定的规则,我们只能遵循喽。
4.6.3 行长
很多Python程序员建议每行不超过80字符,每行注释的行长不超过72字符。
4.6.4 空行
用一行空行将程序的不同部分分开。空行不会影响代码的运行,但会影响代码的可读性。Python解释器根据水平缩进情况来解读代码,但不关心垂直间距。
附Autopep8安装指南,作者:六小登登
Autopep8是一个将python代码自动编排的一个工具,它使用pep8工具来决定代码中的那部分需要被排版,Autopep8可以修复大部分pep8工具中报告的排版问题。
怎么安装呢?打开mac上的终端,输入 sudo pip3 install autopep8,即可安装完毕。
安装结束以后,打开设置–>Tools –> External Tools –> 然后添加,参数配置如下。
怕你们敲键盘累到,参数直接附上
Name: AutoPep8
Description: autopep8 your code
Program: autopep8
Arguments: --in-place --aggressive --aggressive $FilePath$
Working directory: $ProjectFileDir$
Output filters: $FILE_PATH$\:$LINE$\:$COLUMN$\:.*
配置完参数之后,在我们的代码里直接 右键 选择 External Tools–> Autopep8,你就能看到效果啦。
这里我要补充一句,Autopep8需要满足一些条件才能使用,否则会报错。文件路径中或文件名中含有中文、空格等字符,就会导致该错误的产生。
所以当你的Autopep8无法正常启用,报错的时候,请看看是不是在这块出了问题。
下一章的内容是if,也就是分支。啊哈~循环、分支、嵌套,搭配上列表,外号叫丧心病狂四大天王。
那么,下章再见吧~
胭惜雨
2021年02月02日