Python
内置容器与推导式
按业务语义选择列表、元组、字典和集合,并用推导式完成清晰的数据转换。
发布于 2026年7月23日
内置容器与推导式
Python 的容器不是可以随意互换的语法糖。列表强调顺序,元组表达稳定记录,字典建立键到值的映射,集合表达唯一性和成员关系。
一、学习目标
- 按业务语义选择列表、元组、字典和集合
- 掌握切片、排序、解包和循环技巧
- 用推导式表达清晰的数据转换
- 避免循环中修改容器和无意共享引用
- 为任务列表实现筛选与统计
二、列表:有序可变序列
tasks = ["阅读文档", "编写测试", "构建 wheel"]
tasks.append("发布")
first = tasks[0]
last_two = tasks[-2:]
切片创建新的列表:
copy = tasks[:]
reverse = tasks[::-1]
排序有两种形式:
sorted_tasks = sorted(tasks, key=str.casefold)
tasks.sort(key=str.casefold)
sorted 返回新列表;list.sort 原地修改并返回 None。需要保留原顺序时优先使用 sorted。
三、元组:稳定的组合值
task_row = (1, "阅读文档", "todo")
task_id, title, status = task_row
元组自身不可变,适合表达字段位置固定的短记录,也能作为字典键(前提是内部元素均可哈希)。字段较多或需要清晰名称时,应使用 NamedTuple 或 dataclass。
单元素元组依赖逗号:
only_one = ("todo",)
四、字典:键值映射
task = {"id": 1, "title": "阅读文档", "status": "todo"}
print(task["title"])
不确定键是否存在时:
description = task.get("description", "")
遍历键和值:
for key, value in task.items():
print(key, value)
合并配置时,右侧覆盖左侧:
defaults = {"database": "tasks.db", "verbose": False}
user = {"verbose": True}
settings = defaults | user
不要用 dict.get 掩盖必填字段缺失。业务必填数据应使用索引访问或显式校验,让错误尽早暴露。
五、集合:唯一性与成员关系
allowed_statuses = {"todo", "done"}
status = "doing"
if status not in allowed_statuses:
raise ValueError(f"未知状态:{status}")
集合适合去重、交集和差集:
requested = {"read", "write", "delete"}
granted = {"read", "write"}
missing = requested - granted
集合不表达稳定展示顺序。输出给用户前应排序。
空集合必须写成 set();{} 创建的是空字典。
六、推导式
筛选未完成任务:
tasks = [
{"id": 1, "title": "阅读", "status": "todo"},
{"id": 2, "title": "测试", "status": "done"},
]
todo_titles = [
task["title"]
for task in tasks
if task["status"] == "todo"
]
建立 ID 索引:
tasks_by_id = {task["id"]: task for task in tasks}
提取状态集合:
statuses = {task["status"] for task in tasks}
推导式适合“一次映射加一次简单过滤”。如果包含多层条件、异常处理或副作用,普通循环通常更清楚。
七、解包与循环技巧
for index, task in enumerate(tasks, start=1):
print(index, task["title"])
并行遍历:
ids = [1, 2]
titles = ["阅读", "测试"]
for task_id, title in zip(ids, titles, strict=True):
print(task_id, title)
strict=True 会在长度不一致时抛出 ValueError,避免静默丢弃多余元素。
扩展解包:
first, *middle, last = ["规划", "编码", "测试", "发布"]
八、统计任务
from collections import Counter
status_counts = Counter(task["status"] for task in tasks)
print(status_counts["todo"])
print(status_counts["done"])
按状态分组:
from collections import defaultdict
grouped: dict[str, list[dict[str, object]]] = defaultdict(list)
for task in tasks:
grouped[str(task["status"])].append(task)
标准库的 Counter、defaultdict、deque 经常比手写状态管理更明确。
九、常见错误
循环时删除元素
for task in tasks:
if task["status"] == "done":
tasks.remove(task)
这会跳过元素。应构建新列表:
tasks = [task for task in tasks if task["status"] != "done"]
重复引用同一内层列表
matrix = [[0] * 3] * 3
matrix[0][0] = 1
三行共享同一个列表。应写:
matrix = [[0] * 3 for _ in range(3)]
十、练习与自测
- 按状态统计任务数量,并按状态名称排序输出。
- 建立
id -> task索引,检测重复 ID。 - 用集合找出“请求权限”和“已授予权限”的差集。
自测:
- 为什么集合不适合直接作为展示顺序?
sorted与list.sort有何不同?- 什么时候应该把推导式改写为普通循环?
十一、官方资料
上一篇:语法、对象与数据类型 | 下一篇:控制流、函数与作用域