飞翔飞翔
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
  • 数据库

    • SQL教程
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

    • Redis教程
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
  • 数据库

    • SQL教程
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

    • Redis教程
联系
阿里云
  • 学习路径
  • 第1章 Python简介

    • Python是什么
    • 安装与运行
    • 交互式解释器
    • 注释与编码规范
  • 第2章 变量与数据类型

    • 变量与对象
    • 整数 int
    • 浮点数 float
    • 复数 complex
    • 布尔值 bool
    • 字符串 str
    • 空值 None
    • 类型转换
  • 第3章 运算符与表达式

    • 算术运算符
    • 比较运算符
    • 赋值运算符
    • 逻辑运算符
    • 位运算符
    • 身份与成员运算符
    • 海象运算符
    • 运算符优先级
  • 第4章 流程控制

    • if 语句
    • if-else 语句
    • if-elif-else 语句
    • match-case 语句
    • 条件表达式(三元运算符)
    • while 循环
    • for 循环
    • range 函数
    • break 与 continue
    • 循环的 else 子句
    • pass 语句
  • 第5章 数据结构

    • 列表创建与索引
    • 列表方法
    • 列表推导式
    • 元组
    • 序列解包
    • 集合
    • 字典创建与访问
    • 字典方法
    • 字典推导式
    • range 对象
  • 第6章 函数

    • 定义函数
    • 位置参数与关键字参数
    • 默认参数
    • 可变参数
    • 解包实参
    • 函数返回值
    • lambda 表达式
    • 文档字符串与注解
    • 作用域与命名空间
    • global 与 nonlocal
  • 第7章 模块与包

    • 模块导入
    • 模块搜索路径
    • 包与相对导入
    • 标准库概览
  • 第8章 文件与输入输出

    • 文件读写
    • 上下文管理器
    • 字符串格式化
    • JSON 与 CSV
  • 第9章 面向对象

    • 类与对象
    • 方法
    • 实例变量与类变量
    • 私有变量
    • 继承
    • 多重继承
    • 魔术方法
    • 属性装饰器
    • 数据类 dataclass
  • 第10章 异常处理

    • 语法错误与异常
    • try-except
    • 异常链与 raise
    • 清理操作
    • 自定义异常
  • 第11章 迭代器与生成器

    • 迭代器协议
    • 生成器
    • 生成器表达式
    • 迭代工具
  • 第12章 高级特性

    • 装饰器
    • 函数式编程
  • 第13章 工程实践

    • 测试与调试
    • 代码质量
    • 虚拟环境

字典推导式

字典推导式(dictionary comprehension)与列表推导式语法相似,使用花括号 {} 包裹,内部格式为 key_expression: value_expression for ...。它提供了一种紧凑、高效的方式来从可迭代对象构建字典。

基本语法

字典推导式的结构是 {k: v for item in iterable},其中 k 和 v 是基于 item 的表达式:

# 从数字序列创建平方映射
squares = {x: x**2 for x in range(6)}
# {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

# 从列表创建长度映射
words = ['apple', 'banana', 'cherry']
lengths = {w: len(w) for w in words}
# {'apple': 5, 'banana': 6, 'cherry': 6}

推导式中的键表达式必须产生可哈希对象,否则会在运行时抛出 TypeError:

# 错误:列表不可哈希
{[x]: x for x in range(3)}   # TypeError: unhashable type: 'list'

带条件过滤

在 for 子句后添加 if 条件,可以筛选满足条件的键值对:

# 只保留偶数键
{d: d**2 for d in range(10) if d % 2 == 0}
# {0: 0, 2: 4, 4: 16, 6: 36, 8: 64}

# 过滤值满足条件的项
prices = {'apple': 3.5, 'banana': 1.2, 'cherry': 8.0}
{fruit: price for fruit, price in prices.items() if price > 2.0}
# {'apple': 3.5, 'cherry': 8.0}

条件过滤在键值对生成之前执行,因此可以基于原始数据做筛选,再对通过筛选的数据做转换。

交换键值

字典推导式常用于交换字典的键和值。前提是原字典的值必须可哈希,否则不能作为新字典的键:

# 值可哈希,直接交换
d = {'a': 1, 'b': 2, 'c': 3}
{v: k for k, v in d.items()}
# {1: 'a', 2: 'b', 3: 'c'}

# 值重复时,后面的键覆盖前面的
# 若 d = {'a': 1, 'b': 1},结果为 {1: 'b'}

当值有重复时,由于字典键的唯一性,后面的键值对会覆盖前面的。如果需要保留所有映射,应将值收集为列表:

from collections import defaultdict

d = {'a': 1, 'b': 1, 'c': 2}
result = defaultdict(list)
for k, v in d.items():
    result[v].append(k)
# defaultdict(<class 'list'>, {1: ['a', 'b'], 2: ['c']})

与 zip 结合

zip() 函数将多个可迭代对象打包成元组序列,与字典推导式配合可以优雅地合并平行数据:

names = ['jack', 'sape', 'guido']
phones = [4098, 4139, 4127]

# 推导式写法
{name: phone for name, phone in zip(names, phones)}
# {'jack': 4098, 'sape': 4139, 'guido': 4127}

# 更简洁的内置写法(推荐)
dict(zip(names, phones))
# {'jack': 4098, 'sape': 4139, 'guido': 4127}

当序列长度不一致时,zip 以最短序列为准,多余元素被忽略。Python 3.10+ 的 zip(strict=True) 可以在长度不匹配时抛出异常。

推导式在需要同时过滤或转换时更有优势:

# 只保留名字长度大于4的项
{name: phone for name, phone in zip(names, phones) if len(name) > 4}
# {'sape': 4139, 'guido': 4127}

# 对值做转换
{name: phone + 1000 for name, phone in zip(names, phones)}
# {'jack': 5098, 'sape': 5139, 'guido': 5127}

嵌套与复杂表达式

字典推导式支持嵌套循环和复杂键值表达式,但嵌套层次过深会损害可读性:

# 展平嵌套字典的某一层
nested = {'a': {'x': 1, 'y': 2}, 'b': {'x': 3, 'y': 4}}
{outer + '_' + inner: val
 for outer, inner_dict in nested.items()
 for inner, val in inner_dict.items()}
# {'a_x': 1, 'a_y': 2, 'b_x': 3, 'b_y': 4}

对于两层以上的嵌套结构,建议使用普通循环,代码更易维护。

条件表达式在值中

推导式的值表达式部分可以使用三元条件表达式,实现更灵活的逻辑:

scores = {'Alice': 85, 'Bob': 72, 'Charlie': 90}

# 根据分数打标签
{name: ('pass' if s >= 60 else 'fail') for name, s in scores.items()}
# {'Alice': 'pass', 'Bob': 'pass', 'Charlie': 'pass'}

# 同时过滤和转换
{name: s for name, s in scores.items() if s >= 80}
# {'Alice': 85, 'Charlie': 90}

与 setdefault 的对比

字典推导式适合"已知全部数据,一次性构建"的场景;而 setdefault 或 defaultdict 适合"边遍历边累积"的增量构建。选择哪种方式取决于数据是否已完整可用。

上一页
字典方法
下一页
range 对象