一、什么是字典推导式?
字典推导式(Dictionary Comprehension) 是 Python 中一种简洁的语法,用于从可迭代对象(如列表、元组、range等)中快速创建字典。它与列表推导式类似,但生成的是字典而不是列表。
字典推导式的基本思想是:对可迭代对象中的每个元素应用一个表达式,生成键值对,从而构建新的字典。
# 传统方式:用 for 循环创建字典squares = {}for x inrange(5): squares[x] = x**2print(squares) # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}# 字典推导式方式squares = {x: x**2for x inrange(5)}print(squares) # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
二、基本语法
{键表达式: 值表达式 for 变量 in 可迭代对象}
- • 键表达式:对每个元素计算的表达式,结果将作为新字典的键。
- • 值表达式:对每个元素计算的表达式,结果将作为新字典的值。
- • 变量:代表可迭代对象中的每个元素的临时变量名。
- • 可迭代对象:任何可迭代的对象(如列表、range、字符串、元组等)。
执行过程:
三、基本示例
3.1 从 range 生成数字及其平方
squares = {x: x**2for x inrange(1, 6)}print(squares) # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
3.2 从列表中创建字典(元素作为键)
fruits = ["苹果", "香蕉", "橙子"]# 将水果名作为键,长度作为值fruit_dict = {fruit: len(fruit) for fruit in fruits}print(fruit_dict) # {'苹果': 2, '香蕉': 2, '橙子': 2}
3.3 使用 enumerate 生成索引映射
colors = ["红", "绿", "蓝"]# 索引作为键,颜色作为值color_dict = {index: color for index, color inenumerate(colors)}print(color_dict) # {0: '红', 1: '绿', 2: '蓝'}
四、带条件的字典推导式
可以在字典推导式中添加 if 条件,筛选满足条件的元素。
语法:
{键表达式: 值表达式 for 变量 in 可迭代对象 if 条件}
numbers = [1, 2, 3, 4, 5, 6]# 只保留偶数的平方even_squares = {x: x**2for x in numbers if x % 2 == 0}print(even_squares) # {2: 4, 4: 16, 6: 36}
也可以对键和值分别应用条件(但条件只能筛选元素,不能分别筛选键和值,因为键值对是基于同一个元素生成的)。
五、从两个列表创建字典(使用 zip)
如果有两个列表,一个作为键,一个作为值,可以用 zip 将它们配对,然后用字典推导式创建字典。
keys = ["name", "age", "city"]values = ["张三", 25, "北京"]person = {keys[i]: values[i] for i inrange(len(keys))}# 更简洁的方式:person = {k: v for k, v inzip(keys, values)}print(person) # {'name': '张三', 'age': 25, 'city': '北京'}
zip 将两个列表打包成元组对,然后解包赋值给 k, v。
如果两个列表长度不一致,zip 会按最短的截断。
六、嵌套循环的字典推导式
字典推导式中也可以使用多个 for 子句,相当于嵌套循环。
# 生成坐标点字典,键为 (x, y),值为 x*ypoints = {(x, y): x*y for x inrange(3) for y inrange(3)}print(points)# {(0, 0): 0, (0, 1): 0, (0, 2): 0, (1, 0): 0, (1, 1): 1, (1, 2): 2, (2, 0): 0, (2, 1): 2, (2, 2): 4}
等价于:
points = {}for x inrange(3):for y inrange(3): points[(x, y)] = x*y
七、交换字典的键和值
使用字典推导式可以方便地交换键和值(前提是值是可哈希且唯一的,否则会丢失重复值)。
original = {"a": 1, "b": 2, "c": 3}swapped = {value: key for key, value in original.items()}print(swapped) # {1: 'a', 2: 'b', 3: 'c'}
如果原值不唯一,后面的键会覆盖前面的。
original = {"a": 1, "b": 1}swapped = {value: key for key, value in original.items()}print(swapped) # {1: 'b'} # 只保留了最后一个
八、与 for 循环的对比
字典推导式通常更高效,也更 Pythonic。但过于复杂的推导式可能影响可读性,此时应使用普通循环。
九、注意事项
- 1. 键必须唯一:如果生成的键重复,后面的键值对会覆盖前面的。
- 2. 键必须可哈希:键必须是不可变类型(如整数、字符串、元组等),列表、字典等不能作为键。
- 3. 可读性:不要在一个推导式中塞入太多逻辑,否则难以理解。嵌套循环或复杂条件建议拆分成普通循环。
- 4. 作用域:推导式中的临时变量不会污染外部命名空间。
- 5. 与生成器表达式的区别:字典推导式直接生成完整字典,占用内存;而生成器表达式(用小括号)逐个生成,节省内存,但不能直接得到字典。
十、实战案例
案例1:统计字符串中字符出现次数
text = "hello world"# 统计每个字符(排除空格)的出现次数char_count = {ch: text.count(ch) for ch inset(text) if ch != ' '}print(char_count) # {'h': 1, 'e': 1, 'l': 3, 'o': 2, 'w': 1, 'r': 1, 'd': 1}
注意:这里用 set(text) 去重,避免重复计算。
案例2:将列表中的单词映射为大写形式
words = ["python", "java", "c++", "javascript"]upper_dict = {word: word.upper() for word in words}print(upper_dict) # {'python': 'PYTHON', 'java': 'JAVA', 'c++': 'C++', 'javascript': 'JAVASCRIPT'}
案例3:根据条件修改值
scores = {"小明": 85, "小红": 92, "小刚": 78}# 将及格(>=60)的分数标记为"Pass",否则为"Fail"result = {name: "Pass"if score >= 60else"Fail"for name, score in scores.items()}print(result) # {'小明': 'Pass', '小红': 'Pass', '小刚': 'Pass'}
案例4:读取文件构建字典
假设有一个文件 data.txt 内容为:
apple 5banana 3orange 8
可以用字典推导式读取并构建字典:
withopen("data.txt") as f: fruit_count = {line.split()[0]: int(line.split()[1]) for line in f}print(fruit_count) # {'apple': 5, 'banana': 3, 'orange': 8}
案例5:使用字典推导式生成九九乘法表(键为元组)
multiplication = {(i, j): i*j for i inrange(1, 10) for j inrange(1, i+1)}print(multiplication)# {(1, 1): 1, (2, 1): 2, (2, 2): 4, (3, 1): 3, (3, 2): 6, (3, 3): 9, ...}
十一、总结
- • 基本语法:
{key_expr: value_expr for item in iterable}
掌握字典推导式,能让你的代码更 Pythonic,更简洁优雅。