当前位置:首页>python>Python:字典推导式

Python:字典推导式

  • 2026-09-10 12:09:36
Python:字典推导式

字典推导式(Dictionary Comprehension)是 Python 中用于生成字典的一种简洁语法,它可以把遍历、条件筛选、键值转换和结果收集写在一个表达式中,适合根据已有数据快速建立键与值之间的对应关系。

字典推导式与列表推导式和集合推导式的基本结构相似,但输出表达式由键和值两部分组成,生成的结果是字典。

一、什么是字典推导式

1、基本语法

字典推导式使用 { } 生成字典,基本形式为:

{键表达式: 值表达式 for 变量 in 可迭代对象}

例如,生成数字及其平方之间的对应关系:

squares = {    x: x ** 2    for x in range(5)}print(squares)

输出:

{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

这段字典推导式可以分成三个部分:

x: x ** 2       # 生成当前键和值for x           # 将当前元素依次绑定给 xin range(5)     # 指定要遍历的数据

使用普通循环可以写成:

squares = {}for x in range(5):    squares[x] = x ** 2print(squares)

普通循环通过赋值语句向字典中写入键值对,字典推导式则将遍历、计算和收集写在一个表达式中。

2、字典推导式的结果特点

(1)字典由键值对组成

列表推导式和集合推导式只需要一个输出表达式,字典推导式则必须同时生成键和值。在输出表达式中,冒号左侧生成键,右侧生成对应的值。

键和值都可以根据当前元素进行计算:

mapping = {    f"item_{x}": x * 10    for x in range(3)}print(mapping)

输出:

{'item_0': 0, 'item_1': 10, 'item_2': 20}

(2)字典中的键不能重复

字典中的每个键都是唯一的。如果不同元素生成了相同的键,后生成的值会覆盖该键原来的值。

pairs = [    ("name", "张三"),    ("city", "长沙"),    ("name", "李四")]result = {    key: value    for key, value in pairs}print(result)

输出:

{'name': '李四', 'city': '长沙'}

键 "name" 出现了两次,后面的 "李四" 覆盖了前面的 "张三"。

集合会合并重复元素;字典遇到重复键时,则会用后生成的值覆盖该键原来的值。

3、字典键必须可哈希

字典通过哈希机制查找和管理键,因此字典的键必须是可哈希对象(Hashable Object)。

数值、字符串以及由可哈希元素组成的元组,都可以作为字典键:

points = {    (x, x ** 2): x    for x in range(4)}print(points)

输出可能为:

{(0, 0): 0, (1, 1): 1, (2, 4): 2, (3, 9): 3}

列表、字典和普通集合不能作为字典键。例如:

mapping = {    [x, x ** 2]: x    for x in range(4)}

运行后会引发 TypeError,因为列表不可哈希。

字典的值没有这一限制,可以是数值、字符串、列表、字典或其他对象。

二、带条件的字典推导式

字典推导式中的条件主要有两种用途:

• 条件筛选:决定当前遍历到的元素是否参与键值对生成

• 条件表达式:根据条件选择当前要生成的键或值

两种写法中,if 所在的位置不同。

1、条件筛选

在 for 后面添加 if,可以只处理满足条件的元素。

基本语法为:

{

键表达式: 值表达式

    for 变量 in 可迭代对象

    if 条件

}

例如,只保留偶数及其平方:

even_squares = {    x: x ** 2    for x in range(10)    if x % 2 == 0}print(even_squares)

输出:

{0: 0, 2: 4, 4: 16, 6: 36, 8: 64}

只有满足 x % 2 == 0 的数字才会参与键值对生成。

2、条件表达式

条件表达式可以用在键表达式或值表达式中,根据条件选择不同结果。

例如,根据成绩生成是否及格的状态:

scores = {    "张三": 86,    "李四": 58,    "王五": 73}status = {    name: "pass" if score >= 60 else "fail"    for name, score in scores.items()}print(status)

输出:

{'张三': 'pass', '李四': 'fail', '王五': 'pass'}

这里的键仍然使用学生姓名,值则由条件表达式决定。

条件表达式也可以用于生成键,但需要注意:如果不同元素生成相同的键,后面的值会覆盖前面的值。

三、包含多个 for 子句的字典推导式

字典推导式中可以连续使用多个 for 子句,表示多层循环。

基本语法为:

{

键表达式: 值表达式

    for 变量1 in 可迭代对象1

    for 变量2 in 可迭代对象2

}

多个 for 子句从左到右,对应普通循环由外到内的顺序。

例如,以坐标元组为键,保存对应坐标的乘积:

products = {    (x, y): x * y    for x in range(1, 3)    for y in range(1, 4)}print(products)

输出:

{    (1, 1): 1,    (1, 2): 2,    (1, 3): 3,    (2, 1): 2,    (2, 2): 4,    (2, 3): 6}

在这段代码中:

for x 是外层循环;

for y 是内层循环;

(x, y) 是字典键;

x * y 是对应的值。

多个 for 子句后面也可以添加筛选条件。每组满足条件的变量取值都会用于计算键表达式和值表达式,再生成一个键值对。

四、字典推导式的典型应用场景

字典推导式适合建立索引、转换现有字典、组合对应数据,以及生成模型所需的编号映射。

1、筛选并转换现有字典

遍历已有字典时,可以使用 items() 同时取得键和值。

例如,只保留价格不低于 10 的商品,并计算九折价格:

prices = {    "apple": 8.0,    "banana": 12.0,    "orange": 15.0,    "pear": 6.0}discounted_prices = {    name: round(price * 0.9, 2)    for name, price in prices.items()    if price >= 10}print(discounted_prices)

输出:

{'banana': 10.8, 'orange': 13.5}

这个字典推导式同时完成了条件筛选和值转换。

2、将记录转换为查询索引

实际数据经常由多条字典记录组成。可以选择其中具有唯一性的字段作为键,建立便于查询的索引。

users = [    {"id": 101, "name": "张三", "city": "长沙"},    {"id": 102, "name": "李四", "city": "北京"},    {"id": 103, "name": "王五", "city": "上海"}]users_by_id = {    user["id"]: user    for user in users}print(users_by_id[102])

输出:

{'id': 102, 'name': '李四', 'city': '北京'}

转换后,可以直接通过用户编号查找对应记录,不必每次遍历整个列表。

作为键的字段应具有唯一性。若多条记录使用同一个编号,后面的记录会覆盖前面的记录。

3、组合位置对应的数据

zip() 可以同时遍历多组位置对应的数据。与字典推导式配合,可以建立字段与数据之间的对应关系,并在生成过程中进行转换。

fields = ["name", "email", "city"]values = [" 张三 ", "ZHANG3@EXAMPLE.COM", " 长沙 "]record = {    field: value.strip()    for field, value in zip(fields, values)}print(record)

输出:

{'name': '张三', 'email': 'ZHANG3@EXAMPLE.COM', 'city': '长沙'}

zip() 建立字段和值之间的对应关系,字典推导式则对值进行清洗并生成字典。

当多个可迭代对象长度不同时,zip() 会在最短的对象结束时停止。

4、为 AI 词元建立编号映射

在自然语言处理任务中,模型通常需要将词元(Token)映射为整数编号。

可以使用 enumerate() 与字典推导式建立词元到编号的映射:

tokens = [    "<PAD>",    "<UNK>",    "python",    "ai",    "model",    "data"]token_to_id = {    token: index    for index, token in enumerate(tokens)}print(token_to_id)

输出:

{    '<PAD>': 0,    '<UNK>': 1,    'python': 2,    'ai': 3,    'model': 4,    'data': 5}

enumerate() 提供连续编号,字典推导式则建立词元到编号的查询关系。

词元列表还应避免包含重复词元。

此外,编号顺序应保持稳定。如果词元来自集合,应先排序或按照明确规则组织成列表,再分配编号,避免不同运行中产生不一致的映射。

五、常见问题及使用建议

1、无须转换时直接使用 dict()

如果数据已经由键值对组成,并且不需要筛选或转换,可以直接使用 dict():

keys = ["name", "city"]values = ["张三", "长沙"]record = dict(zip(keys, values))

下面的字典推导式虽然也能得到相同结果,但没有必要:

record = {    key: value    for key, value in zip(keys, values)}

需要计算键、转换值或添加筛选条件时,字典推导式更合适。

2、注意重复键覆盖

字典推导式生成键时,应确保键表达式符合预期。

例如,将字符串统一转换为小写后,原本不同的字符串可能生成相同的键:

names = ["Alice", "ALICE", "Bob"]mapping = {    name.lower(): name    for name in names}print(mapping)

输出:

{'alice': 'ALICE', 'bob': 'Bob'}

"Alice" 和 "ALICE" 都生成键 "alice",因此后面的值覆盖了前面的值。

3、不适合直接完成计数或分组

字典推导式遇到重复键时只会覆盖已有值,不会自动累加或合并数据。

因此,下面的写法不能正确统计字符出现次数:

text = "banana"counts = {    character: 1    for character in text}

结果只表示出现过哪些字符,每个值都是 1。

需要统计频次时,可以使用 collections.Counter:

from collections import Countercounts = Counter(text)

需要将多条数据按键分组时,通常应使用普通循环、defaultdict 或其他专门方法。

4、避免堆叠过多逻辑

字典推导式适合结构简单、目的明确的字典生成任务。

当键和值都包含复杂计算,或者推导式中包含多个循环、多个条件和异常处理时,普通循环通常更容易阅读、调试和维护。

5、避免副作用操作

字典推导式的主要目的是生成字典,与其他推导式一样,不适合只用于输出、写入文件或修改外部状态。

📘 小结

字典推导式可以在遍历过程中生成键值对,并完成键值转换和条件筛选。它适合建立查询索引、转换现有字典、组合对应数据和构建编号映射。使用时应注意字典键必须可哈希,重复键会覆盖原有值,计数和分组任务通常应使用其他方法。

“点赞有美意,赞赏是鼓励”

最新文章

随机文章