Python怎么遍历字典的键、值和键值对
在 Python 日常开发中,字典(dict)是存储结构化映射数据的核心容器。无论是解析来自后端接口的 JSON 响应、读取服务配置项,还是统计字频,遍历字典都是最高频的基础操作。掌握 Python 遍历字典的完整方法,关键在于按需选择三个维度的提取路径:直接或通过 keys() 遍历键、通过 values() 遍历值,以及通过 items() 同步解包键值对。
一、遍历字典的键(Keys)
当你只需要读取字典中存在的所有属性名称,或者仅需要依据键做逻辑判断时,遍历键是最直接的操作。在 Python 中,遍历字典的键有两种书写方式:直接遍历字典对象与显式调用 .keys() 方法。
1. 直接遍历字典(推荐的标准写法)
在 Python 的迭代协议中,字典本身就是一个可迭代对象,其默认迭代器产出的就是字典的键。因此,最简洁、符合 Pythonic 风格的写法是直接对字典使用 for 循环:
# 准备演示字典
user_profile = {
"id": 1024,
"name": "Alice",
"role": "Admin",
"status": "Active"
}
# 方式一:直接遍历字典对象
for key in user_profile:
print(key)
# 示例输出:
# id
# name
# role
# status
2. 显式调用 dict.keys()
你也可以使用字典的内置方法 user_profile.keys()。这种方式与直接遍历字典在运行效率与产出结果上完全一致:
# 方式二:显式调用 keys() 方法
for key in user_profile.keys():
print(key)
选择依据:在普通的 for 循环中,直接写 for key in d: 更干净自然;而当你需要向阅读代码的人强调“此处仅处理键集合”,或者需要进行集合运算(如求两个字典键的交集 d1.keys() & d2.keys())时,使用 .keys() 会使语义更加清晰。
二、遍历字典的值(Values)
在很多业务场景下,我们并不关心字段名称,只关心字典中保存的实际数值。例如计算商品总价、统计用户得分总和、或者判断是否有任意一项状态不合规。这时应使用 .values() 方法。
实用场景:数值累加与数据清洗
# 学生期末成绩字典
student_scores = {
"Math": 95,
"English": 88,
"Physics": 92,
"Chemistry": 85
}
# 遍历所有科目的成绩并计算均分
total_score = 0
for score in student_scores.values():
total_score += score
average_score = total_score / len(student_scores)
print(f"总分: {total_score}, 平均分: {average_score:.2f}")
# 示例输出:
# 总分: 360, 平均分: 90.00
因为 student_scores.values() 返回的是一个可迭代的视图对象,在不需要显式编写 for 循环体时,还可以直接将其传递给内置聚合函数,如 sum(student_scores.values()) 或 max(student_scores.values()),执行速度更快且代码极其精炼。
三、遍历字典的键值对(Items)与元组解包
当正文逻辑同时依赖字段名(键)和对应内容(值)时,切忌使用 for k in d: val = d[k] 这种先取键再按键寻址的反模式。频繁哈希查找会带来额外的计算开销。最标准、高效的解法是使用 .items() 方法结合元组解包。
完整代码示例:格式化打印与解包
server_config = {
"host": "127.0.0.1",
"port": 8080,
"timeout": 30,
"debug": True
}
# 推荐解包写法:同时获取 key 和 value
for key, value in server_config.items():
print(f"配置项: {key:<10} => 当前值: {value}")
# 示例输出:
# 配置项: host => 当前值: 127.0.0.1
# 配置项: port => 当前值: 8080
# 配置项: timeout => 当前值: 30
# 配置项: debug => 当前值: True
如果在 for 后只写了一个接收变量,例如 for item in server_config.items():,那么 item 将是一个包含两个元素的元组 ('host', '127.0.0.1')。显式提供两个变量 k, v 能让代码阅读体验更佳。
四、三种遍历方式的特征与选型对比
在 Python 3 中,.keys()、.values() 和 .items() 返回的都不是普通的列表(list),而是视图对象(View Objects)(类型分别为 dict_keys、dict_values 和 dict_items)。
视图对象的两大关键特性:
- 零内存冗余(惰性开销):与 Python 2 中
.keys()直接在内存中复制一份静态列表不同,Python 3 的视图对象不会分配容纳所有键/值的额外内存,因此即便遍历上千万条数据的巨型字典,内存占用也始终保持极低。 - 动态联动反映:视图对象直接绑定原字典底层哈希桶。如果字典在外部发生修改,尚未完成遍历的视图会实时反映这些变更。
五、避坑指南:遍历中修改字典的异常与三种安全模式
许多初学者在编写“删除某些过期键”或“按条件更新字段”时,往往习惯直接在循环体内部调用 del 或新增键:
# 错误示例:边遍历边删除键
scores = {"a": 60, "b": 45, "c": 80}
for k, v in scores.items():
if v < 60:
del scores[k] # 触发致命错误!
# 运行时报错:
# RuntimeError: dictionary changed size during iteration
异常原因:Python 的字典迭代器在启动时会记录哈希表当前的条目容量计数器。在迭代过程中,如果执行新增或删除键的操作,哈希表的内存结构会发生改变或发生重哈希(Rehash),这会导致迭代器内部的偏移索引紊乱。为了防止发生未定义行为或死循环,Python 解释器会主动抛出 RuntimeError 阻断执行。
安全方案代码实操:
target_dict = {"a": 10, "b": 20, "c": 30, "d": 40}
# 方案 A 实操:使用 list() 快照进行原位修改
for k in list(target_dict.keys()):
if target_dict[k] < 25:
del target_dict[k]
print("方案 A 处理后:", target_dict)
# 示例输出:方案 A 处理后: {'c': 30, 'd': 40}
# 方案 B 实操:使用字典推导式直接过滤出新字典
raw_data = {"apple": 5, "banana": 0, "orange": 12}
filtered_data = {k: v for k, v in raw_data.items() if v > 0}
print("方案 B 过滤后:", filtered_data)
# 示例输出:方案 B 过滤后: {'apple': 5, 'orange': 12}
六、进阶技巧:排序遍历与索引编号
1. 按键或按值排序后遍历
字典本身维护的是插入顺序。如果需要按照字母表或数值大小有序输出,可以配合 sorted() 函数:
inventory = {"banana": 30, "apple": 50, "cherry": 20}
# 1. 按照键(水果名称字母顺序)排序遍历
for fruit in sorted(inventory):
print(f"{fruit}: {inventory[fruit]}")
# 示例输出:
# apple: 50
# banana: 30
# cherry: 20
# 2. 按照值(库存数量由小到大)排序遍历
for fruit, count in sorted(inventory.items(), key=lambda item: item[1]):
print(f"低库存预警: {fruit} -> {count}")
# 示例输出:
# 低库存预警: cherry -> 20
# 低库存预警: banana -> 30
# 低库存预警: apple -> 50
2. 在遍历时获取循环序号(enumerate)
如果业务中需要类似“序号 1、2、3”的自增行号,可直接对 .items() 包装 enumerate() 函数。注意在解包时,外层接收序号,内层元组再解包键值对:
languages = {"Python": 1991, "Java": 1995, "Rust": 2010}
# 采用 (key, value) 括号完成嵌套元组解包
for idx, (lang, year) in enumerate(languages.items(), start=1):
print(f"[{idx}] {lang} 首发于 {year} 年")
# 示例输出:
# [1] Python 首发于 1991 年
# [2] Java 首发于 1995 年
# [3] Rust 首发于 2010 年
总结速查
| 遍历目标 | 推荐语法 | 底层返回值类型 | 核心关注点 |
|---|---|---|---|
| 只遍历键 | for k in d: |
dict_keys |
代码最简练,默认迭代器行为。 |
| 显式强调键 | for k in d.keys(): |
dict_keys |
可读性好,支持集合运算(并集、交集)。 |
| 只遍历值 | for v in d.values(): |
dict_values |
适用于数值累加、统计或直接传给聚合函数。 |
| 同时遍历键与值 | for k, v in d.items(): |
dict_items |
标准元组解包,性能最优,避免二次哈希查找。 |
| 遍历中删除键 | for k in list(d.keys()): |
list 快照 |
避免 RuntimeError 字典大小变更错误。 |
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









