Python 的容器四件套(列表、元组、字典、集合)是它「脚本语言威力」的主力:一个字典顶 Java 课的 HashMap + getter/setter 全家桶,一个列表切片顶 C 的指针算术。本章讲四件套的性格差异、选型表、以及高频惯用法。数据结构课的线性表、哈希表(第 2、7 章)在这里都有工程实体,对照着学收益翻倍。
lst = [3, 1, 4, 1, 5]
lst.append(9) # 尾加,O(1) 摊还(数据结构课第 1 章的动态数组)
lst.insert(0, 7) # 头插,O(n)(全体后移)
lst.pop() # 尾删并返回
lst.remove(4) # 按值删第一个匹配
lst.sort() # 原地排序(Timsort,数据结构课第 8 章)
lst.reverse()
lst[1:3] # 切片:新列表 [1, 4]
[0] * 5 # [0,0,0,0,0](快速初始化)
len(lst), 5 in lst # 长度、成员判断
sorted(lst) # 返回新列表(不动原列表)
列表是「动态数组」实现(数据结构课第 12 章:连续内存 + 按需扩容),所以尾部操作 O(1)、随机访问 O(1)、头部/中部插入 O(n)(要搬)。高频头插用 collections.deque(双端队列,第 7 章)。
引用语义(第 2 章名字贴的重头戏):b = a 是同一对象,b.append 时 a 也变;真复制用 a.copy()(浅)或 copy.deepcopy(a)(深,嵌套结构必须)。Java 课第 5 章数组的同款坑,Python 里因为默认全是引用,杀伤面更大。
user = {"name": "思源", "age": 21}
user["school"] = "西亚斯" # 增/改
user["name"] # 查:不存在则 KeyError!
user.get("phone", "未填") # 查:带默认值,不炸
"user" in user # 键是否存在
del user["age"] # 删
for k, v in user.items(): # 遍历键值对
print(k, v)
字典是哈希表(数据结构课第 7 章:桶 + 冲突处理),查询 O(1)。三个必会惯用法:
# ① get 带默认:统计词频
for w in words:
count[w] = count.get(w, 0) + 1
# ② setdefault / defaultdict(第 7 章):值是列表的字典
from collections import defaultdict
groups = defaultdict(list)
groups[key].append(item) # 键不存在自动建空列表
# ③ 字典推导式(第 3 章)
squares = {n: n*n for n in range(5)}
字典键的要求:可哈希(不可变:字符串、数字、元组可以;列表不行——数据结构课第 7 章「哈希键稳定性」)。值随便。Python 3.7+ 字典保持插入顺序(哈希表的意外赠品,写有序配置很方便)。
元组 = 不可变列表:point = (3, 4),不能增删改;用途:固定结构的记录(坐标、键值对)、字典的键、函数多返回值(第 3 章)。a, b = b, a 交换变量的魔法,本质是元组打包解包。「可变 vs 不可变」的选型:会变的用列表,当常量记录用的用元组(还能当字典键)。
集合 = 无序不重复,哈希实现:
tags = {"python", "web"}
tags.add("sql") # 增
"python" in tags # O(1) 成员判断(列表是 O(n)!)
a & b, a | b, a - b # 交、并、差(离散数学课第 1 章的运算)
set([1,1,2,2]) # {1,2} 去重神器
去重(set(lst))和成员判断(O(1))是集合两大日常;数学运算直接对标离散数学(交集并集差集,本站离散课第 1 章)。
| 需求 | 用 | 例 |
|---|---|---|
| 有序可变序列 | list | 待办清单 |
| 固定记录 | tuple | 坐标、RGB |
| 键 → 值查询 | dict | 用户档案、计数器 |
| 去重/成员判断 | set | 已见过的 ID |
| 高频头插 | deque | 滑动窗口 |
惯用法合集(背下来,代码量减半):
if not lst: ... # 空列表判空(空序列为 False,Pythonic)
a, b = lst[0], lst[-1] # 首尾
top3 = sorted(scores, reverse=True)[:3] # 前三名
for i, v in enumerate(lst): ... # 带下标遍历
d = dict(zip(keys, values)) # 平行列表变字典
grid = [[0]*3]*3 的三行是同一个列表(乘法复制引用!),改 grid[0][0] 三行全变;正确姿势 [[0]*3 for _ in range(3)]。list(d.keys()) 副本或收集后处理。(x, y): value)。if x in lst 或用异常处理(第 5 章)。