浏览知识库目录

Python

内置容器与推导式

按业务语义选择列表、元组、字典和集合,并用推导式完成清晰的数据转换。

内置容器与推导式

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

元组自身不可变,适合表达字段位置固定的短记录,也能作为字典键(前提是内部元素均可哈希)。字段较多或需要清晰名称时,应使用 NamedTupledataclass

单元素元组依赖逗号:

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)

标准库的 Counterdefaultdictdeque 经常比手写状态管理更明确。


九、常见错误

循环时删除元素

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)]

十、练习与自测

  1. 按状态统计任务数量,并按状态名称排序输出。
  2. 建立 id -> task 索引,检测重复 ID。
  3. 用集合找出“请求权限”和“已授予权限”的差集。

自测:

  • 为什么集合不适合直接作为展示顺序?
  • sortedlist.sort 有何不同?
  • 什么时候应该把推导式改写为普通循环?

十一、官方资料

上一篇:语法、对象与数据类型 | 下一篇:控制流、函数与作用域