列表
一个变量只能存一个东西。而列表可以按顺序存很多东西,都放在一个名字下面。排行榜就是一串按名次排列的分数,一份测验就是一堆题目的集合。一旦你需要管理一组相关的值,你就需要列表了。
创建列表
用方括号括起来,值之间用逗号分隔。列表可以混装任意类型,空列表也是合法且常见的写法,常用来作为后续逐步填充的起点。
scores = [87, 92, 74, 65, 91]
players = ["小明", "小红", "小刚"]
mixed = ["小明", 87, True, 3.14] # 任意类型都行,但不常见
empty = [][] 是个不错的起点。我自己写的很多列表都是这样开始的,空着,等着被填满。 索引和切片
列表用的编号规则和字符串一样:位置从 0 开始,负数从末尾往前数。你可以通过位置读取任意一项。因为列表是可变的,你也可以往某个位置写入新值。
scores = [87, 92, 74, 65, 91]
scores[0] # 87 (第一个)
scores[-1] # 91 (最后一个)
scores[1:3] # [92, 74]
scores[:2] # [87, 92]
scores[::-1] # [91, 65, 74, 92, 87] (反转)
scores[0] = 90 # 可变:成功(字符串会抛出 TypeError)0 开始,负数从末尾往前数,所以 scores[-1] 就是最后一个。像 scores[1:3] 这样的切片会给你一个全新的列表,包含位置 1 和 2。让我停顿了一下的地方是:对于列表,你还可以往某个位置写值,scores[0] = 90,而字符串会拒绝这么做。 添加元素
添加元素有三种方法。append() 把一个元素加到末尾,你几乎每次都会用它。insert() 在指定位置插入元素。extend() 把另一个列表的内容合并进来。
scores = [87, 92, 74]
scores.append(65) # [87, 92, 74, 65]
scores.insert(1, 100) # [87, 100, 92, 74, 65]
scores.extend([55, 71]) # [87, 100, 92, 74, 65, 55, 71]一个常见错误:用 append() 添加一个列表,会把整个列表当作一个元素加进去,导致你得到一个"列表里嵌着列表"的结果。要合并的话该用 extend():
scores.append([55, 71]) # [..., [55, 71]] 嵌套列表,大概不是你想要的
scores.extend([55, 71]) # [..., 55, 71] 合并,正确append() 往末尾加一个元素,是你几乎每次都会用到的方法。insert() 在指定位置插入一个元素,extend() 把另一个列表合并进来。经典的坑:append() 一个列表会得到列表套列表,所以想合并的时候要用 extend()。 删除元素
删除元素有四种工具。remove() 按值查找并删除。pop() 按位置删除并把删掉的元素返回给你。del 按位置删除,但不返回任何值。clear() 清空整个列表。
scores = [87, 92, 74, 65, 91]
scores.remove(74) # 删除第一个值为 74 的元素
scores.pop() # 删除并返回最后一个元素(91)
scores.pop(0) # 删除并返回位置 0 的元素(87)
del scores[1] # 删除位置 1 的元素,没有返回值
scores.clear() # 清空所有元素如果值不在列表中,remove() 会抛出 ValueError。如果你不确定,可以先用 in 检查一下:
if 74 in scores:
scores.remove(74)remove() 按值删除,而且只删第一个匹配项,如果值不存在会抛出 ValueError,所以不确定的时候先用 in 检查一下。pop() 按位置删除并把元素返回给你,del 按位置删除但什么都不返回。 排序
sorted() 返回一个全新的排好序的列表,原来的列表不受影响。.sort() 就地对列表排序,返回 None。这个区别比听起来要重要得多。
scores = [87, 42, 96, 55, 71]
ranked = sorted(scores) # [42, 55, 71, 87, 96] (新列表)
scores.sort() # 就地排序,返回 None
scores.sort(reverse=True) # [96, 87, 71, 55, 42]
result = scores.sort() # result 是 None,不是排好序的列表sorted() 给你一个新的排好序的列表,原来的列表不受影响。.sort() 就地重新排列列表本身,返回 None,所以 x = scores.sort() 会让你得到 None,不是那个列表。我自己在这上面栽过不止一次,才彻底记住。 常用操作
Python 有一批直接作用于列表的内置工具。len()、sum()、min() 和 max() 是你会一直用到的四个。
scores = [87, 92, 74, 65, 91]
len(scores) # 5
sum(scores) # 409
min(scores) # 65
max(scores) # 92
scores.count(87) # 1
scores.index(74) # 2
74 in scores # True
74 not in scores # False
scores.copy() # 浅拷贝
scores.reverse() # 就地反转len()、sum()、min() 和 max() 都可以直接用在列表上,不需要任何额外设置。in 用来判断某个值是否存在,.count() 统计出现次数,.index() 找出第一个匹配项的位置。 遍历
for 循环会逐个遍历列表中的元素。for 后面的变量每一轮都会拿到当前的元素。当你还需要知道位置时,enumerate() 可以同时给你两者,不用自己手动计数。
players = ["小明", "小红", "小刚"]
for player in players:
print(player)
for i, player in enumerate(players, start=1):
print(f"{i}. {player}")
# 1. 小明
# 2. 小红
# 3. 小刚for 和 enumerate() 会在控制流章节详细讲解。简单来说:for player in players 对每个元素运行一次,而 enumerate() 每次迭代都同时给你位置和值。
for 循环逐个遍历列表,for 后面的名字每一轮都会变成当前那一项。当你还想知道位置的时候,enumerate() 会把两者一起给你,你就不用自己维护一个计数器了。让它替我数,省了我不少"差一"的错误。 嵌套列表
列表可以包含其他列表。这就是表示网格或表格的方式:一个由多行组成的列表,每一行本身又是一个由若干值组成的列表。用两组方括号来访问一个元素:第一组选行,第二组选列。
grid = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
]
grid[0] # [1, 2, 3]
grid[1][2] # 6 (第 1 行,第 2 列)grid[1][2],第一组选行,第二组在这一行里再选一次。 可变性:那个坑
几乎每个人都会在这里踩坑。把一个列表赋值给新变量并不会产生拷贝。两个名字指向的是同一个列表。改一个,另一个也会变。要得到一份独立的拷贝,你必须显式地要求一次。
a = [1, 2, 3]
b = a # b 不是拷贝;它指向同一个列表
b.append(4)
print(a) # [1, 2, 3, 4] (变了:a 和 b 是同一个列表)b = a.copy() # 独立的拷贝
b = list(a) # 效果相同
b = a[:] # 也是一样
# 嵌套列表仍然共享内层对象:
matrix = [[1, 2], [3, 4]]
copy = matrix.copy()
copy[0].append(99)
print(matrix) # [[1, 2, 99], [3, 4]] (内层列表是共享的)b = a 不会产生拷贝,两个名字指向同一个列表,所以通过其中一个做的修改会体现在另一个上。要得到独立的列表,你得主动要求一次:.copy()、list(a) 或 a[:]。这一点几乎每个人第一次都会中招,我也不例外。 更多方法
| 方法 | 作用 |
|---|---|
.append(item) | 添加到末尾 |
.insert(i, item) | 在位置 i 插入 |
.extend(iterable) | 添加可迭代对象中的所有元素 |
.remove(value) | 删除第一个匹配的值 |
.pop(i) | 删除并返回位置 i 处的元素(默认:最后一个) |
.clear() | 删除所有元素 |
.index(value) | 第一个匹配项的位置 |
.count(value) | 出现的次数 |
.sort() | 就地排序 |
.reverse() | 就地反转 |
.copy() | 返回一份浅拷贝 |
实战演练
构建一个分数记录器:添加结果,排序,然后打印摘要。
scores = []
scores.append(87)
scores.append(54)
scores.append(92)
scores.append(67)
scores.append(45)
scores.sort(reverse=True)
print(f"排名后的分数: {scores}")
print(f"最高分: {scores[0]}")
print(f"最低分: {scores[-1]}")
print(f"平均分: {sum(scores) / len(scores):.1f}")
print(f"前三名: {scores[:3]}")
