第4章 操作列表

学习目标

  • 高效处理列表中的元素,使用 for 循环遍历列表。
  • 程序结构根据缩进来确定,避免缩进错误。
  • 创建简单数值列表,并执行一些操作。
  • 元组,对不应变化的值提供一定保护。
  • 在代码越来越复杂时设置格式,使其易于阅读。

4.1 遍历整个列表

如果需要对列表中每个元素都执行相同的操作,可使用 Python 中的 for 循环。

假设我们有一个魔术师名单,需要将每个魔术师名字都打印出来。我们先定义一个列表,接下来定义一个 for 循环,让 Python 从列表中取出一个名字,并将其与变量关联。最后,打印前面赋给变量的名字。

magicians = ['alice', 'david', 'carolina']
for magician in magicians:
	print(magician)
# 输出结果
>>>
alice
david
carolina

Python 首先读取第一行代码,获取列表 magicians 中的第一个值‘alice’,并将其与变量 magician 相关联。打印 magician 的值,依然是‘alice’。由于该列表还包含其他值,Python 将返回循环的第一行,获取列表中的下一个名字‘david’,以此类推直到列表中没有了其他的值,程序结束。

可以将代码解释为:对于(for)列表 magicians 中的每位魔术师(magician),都打印(print)该魔术师(magician)的名字。

请牢记:不管列表有多少元素,都将被执行循环指定的步骤。可以给列表中关联每个值的临时变量指定任意名称。最好选择描述单个列表元素的有意义的名称。如下:

for cat in cats:
for dog in dogs:
for item in list_of_items:

在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!")

4.2 避免缩进错误

常见的缩进错误

4.3 创建数值列表

几个帮助你处理数值列表的函数。轻松找出数字列表的最大值、最小值和总和。

>>> digits = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
>>> min(digits)
0
>>> max(digits)
9
>>> sum(digits)
45

range() 函数

差一行为:从指定的第一个值开始数,在到达指定第二个值时停止,因此输出不包含第二个值。
也可只指定一个参数,这样将从 0 开始,例如,range(6) 返回 0~5(含)。

for value in range(1,5):
	print(value)
>>>
1
2
3
4

range() 创建数值列表
要创建数值列表,可用 list() 函数将 range() 做为该函数的参数,结果直接转换为列表

numbers = list(range(1,6))
print(numbers)
>>>
[1,2,3,4,5]

range() 函数指定第三个参数步长来生成数。

even_numbers = list(range(2,11,2))# 从2开始数,不断加2,直到达到或超过终值(11)
print(even_numbers)
>>>
[2,4,6,8,10]

range() 函数几乎能创建任意数值集合。

如何创建一个包含前 10 个整数的平方的列表?

squares = [] # 创建一个空列表
for value in range(1,11): # 使用range遍历1到10
	square = value ** 2 # 计算当前值的平方并赋给临时变量
	squares.append(square) # 将平方值追加到列表的末尾
print(squares)

有时候使用临时变量让代码更易读,但这样做只会让代码无谓地变长。为了让代码更简洁,可不使用临时变量,而是直接将计算得到的值追加到列表末尾:

squares = []
for value in range(1,11):
	squares.append(value**2)
print(squares)

列表推导式

将 for 循环和创建新元素的代码合并成一行,并自动追加新元素。
示例:

>>> squares = [value**2 for value in range(1, 11)]
>>> print(squares)
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
  1. 指定一个描述性的列表名。
  2. 定义一个表达式,用于生成列表中的值。
  3. 编写 for 循环,给表达式提供值。注意,这里的 for 语句末尾没有冒号。

4.4 使用列表的一部分

列表部分元素的处理(切片)

切片(slice):处理列表中部分元素的语法,我们可以通过在索引中添加冒号(:)来获取部分列表,如果没有指定起始索引,Python 将自动从列表开头开始。类似的,我们也可以省略终止索引,也可以使用负数索引来进行切片操作。

示例:一个运动队成员列表

>>> players = ['charles', 'martina', 'michael', 'florence']
>>> print(players[0:3])
['charles', 'martina', 'michael']
# 提取列表第二、三、四元素为子集
>>> print(players[1:4])
['martina', 'michael']
# 没有指定起始索引,从列表开头开始提取
>>> print(players[:3])
['charles', 'martina', 'michael']
# 省略终止索引,提取第三个到列表末尾的所有元素
>>> print(players[2:])
['michael', 'florence']
# 负数索引返回与列表末尾有相应距离的元素,打印最后两名
>>> print(players[-2:])
['michael', 'florence']

注意:可在表示切片的方括号内指定第三个值,告诉 Python 每隔多少元素提取一个。

遍历切片

如果要遍历列表的部分元素,可在 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

复制列表

创建一个包含整个列表的切片,方法是同时省略起始和终止的索引。就是让 Python 创建一个始于第一个元素,终止于最后一个元素的切片,即复制整个列表。
示例:

my_foods = ['pizza', 'falafel', 'carrot cake']
friend_foods = my_foods[:]
print(f"My favorite foods are:{my_foods}")
print(f"\nMy friend's favorite foods are:{friend_foods}")
# 下⾯在每个列表中都添加一种⾷品,并确认每个列表都记录了相应的⼈喜欢的⾷品
my_foods.append('cannoli')
friend_foods.append('ice cream')
print(f"My favorite foods are:{my_foods}")
print(f"\nMy friend's favorite foods are:{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 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 元组

元组(tuple):不可变的列表。一系列不可修改的元素。使用圆括号包裹。定义元组后,可使用索引访问其元素。

相比列表,元组是更简单的数据结构。如果要存储一组在程序的整个生命周期内都不变的值,就可以使用元组。

示例:如果有一个大小不应改变的矩形。可将长宽存储在一个元组中,确保它们是不能修改的:

dimensions = (200,50)
print(dimensions[0])
print(dimensions[1])
# 可尝试修改元组的某个元素,看结果如何
dimensions[0] = 250

注意:严格地说元组是由逗号标识的,圆括号只是让元组看起来更整洁、更清晰。如果你要定义只包含一个元素的元组,必须在这个元素后面加上逗号:my_t=(3,)

创建只包含一个元素的元组通常没有意义,但自动生成的元组有可能只有一个元素。

可以给表示元组的变量重新赋值来修改,相当于重新定义整个元组

dimensions = (200, 50)
print("Original dimensions:")
for dimension in dimensions:
	print(dimension)
dimensions = (400, 100)
print("\nModified dimensions:")
for dimension in dimensions:
	print(dimension)

4.6 设置代码格式

Python 增强提案(Python Enhancement Proposal,PEP)PEP 8 作为最古老的 PEP 之一,向 Python 程序员提供了代码格式设置指南

一些编码的建议(最终应遵循小组中的大多数):

每级缩进都使用四个空格。不要混用制表符(Tab 键)和空格。对文本编辑器进行设置,使其在你按 Tab 键时插入四个空格。常用编辑器支持设置在按下 Tab 键后输入多个空格的自动转换。如果你还没有这样做,现在就去做吧(有关如何设置,请参阅附录 B)。如果混合使用了制表符和空格,可将文件中所有制表符替换为空格。

每行不要超过 79 个字符。对你使用的编辑器进行设置,使其在第 79 个字符处显示一条垂直参考线。使用 79 个字符的标准行长,可以在你屏幕上打开两三个文件的同时,看到各个文件的完整行。还建议注释行长不超过 72 个字符。

建议将程序不同的部分用空行隔开,但不要插入冗余的空行。空行不影响代码运行,但影响可读性。

动手一试

比萨:想出至少三种你喜欢的比萨,将名称存储在一个列表中,再用 for 循环将每种比萨的名称打印出来。

修改这个循环,使其打印包含比萨名称的句子,而不仅仅是比萨的名称。对每种比萨都显示一行输出,示例:I like pepperoni pizza.

在末尾添加一行代码(不包含在 for 循环中),指出你有多喜欢比萨。输出应包含每种比萨的消息,以及一个总结性的句子:I really love pizza!

favorite_pizzas = ['pepperoni', 'hawaiian', 'veggie']
for pizza in favorite_pizzas:
	# print(pizza)
	print(f"I like {pizza} pizza.")
print("I really love pizza!")

动物:想出三种有共同特征的动物,将名称存储在一个列表中,再用 for 循环打印出来。

针对每种动物都打印一个句子:A dog would make a great pet.

在末尾添加一行代码,指出动物的共同之处,如打印句子:Any of these animals would make a great pet!

animals = ["dog","cat","fish"]
for animal in animals:
	# print(animal)
	print(f"A {animal} would make a great pet.")
print("\nAny of these animals would make a great pet!")

数到 20:使用一个 for 循环打印数 1~20(含)。

for number in range(1,21):
	print(number)

100 万:创建一个包含 1~1 百万的列表,再用 for 循环打印出来。(若输出时间太长,按 Ctrl+C 停止或关闭输出窗口。)

numbers = list(range(1,1000001))
for number in numbers:
	print(number)

100 万求和:创建一个包含 1~1 百万的列表,使用min ()max ()核实列表是从 1 开始到 1 百万结束。另外对列表调用函数 sum (),看看 Python 将 1 百万个数相加要多久。

numbers = list(range(1,1000001))
print(min(numbers))
print(max(numbers))
print(sum(numbers))

奇数:通过range ()函数指定第三个参数来创建一个包含 1~20 的奇数列表,再用 for 循环打印出来。

odd_numbers = list(range(1,21,2))
for number in odd_numbers:
	print(number)

3 的倍数:创建一个包含 3~30 内能被 3 整除的列表,再用 for 循环打印出来。

threes = list(range(3,31,3))
for number in threes:
	print(number)

立方:创建一个包含 1~10 的立方数的列表,再用 for 循环打印出来。

cubes = []
for number in range(1,11):
	cube = number**3
	cubes.append(cube)
	
for cube in cubes:
	print(cube)

立方推导式:用列表推导式生成一个包含前 10 个整数的立方。

cubes = [number**3 for number in range(1,11)]
print(cubes)

切片:选择本章中的一个程序,在末尾添加代码,完成以下任务。

favorite_pizzas = ['pepperoni', 'hawaiian', 'veggie']
print(f"The first three items in the list are:")
for item in favorite_pizzas[:3]:
	print(item)
print(f"Three items from the middle of the list are:{favorite_pizzas[0:3]}")
print(f"The last three items in the list are:{favorite_pizzas[-3:]})

你的比萨,我的比萨:在第 1 个比萨程序中,创建列表的副本,并将其赋给变量 friend_pizzas,完成如下任务。

favorite_pizzas = ['pepperoni', 'hawaiian', 'veggie']
friend_pizzas = favorite_pizzas[:]
favorite_pizzas.append("meat lover's")
friend_pizzas.append('pesto') 
print("My favorite pizzas are:")
for pizza in favorite_pizzas:
	print(f"- {pizza}")
print("\nMy friend's favorite pizzas are:")
for pizza in friend_pizzas:
	print(f"- {pizza}")

使用多个循环:为了节省篇幅,程序没有使用 for 循环来打印列表。

自助餐:自助式餐馆提供 5 种简单食品,请将其存储在一个元组中。

menu_items = ( 'rockfish sandwich', 'halibut nuggets', 'smoked salmon chowder', 'salmon burger', 'crab cakes',)

print("You can choose from the following menu items:") 
for item in menu_items:
	print(f"- {item}")
# menu_items[3]= 'g'
menu_items = ( 'rockfish sandwich', 'halibut nuggets', 'smoked salmon chowder', 'black cod tips', 'king crab legs',)
print("\nOur menu has been updated.")
print("You can now choose from the following items:")
for item in menu_items:
	print(f"- {item}")