Python基础指南之字典遍历的核心方法详解
一、开篇:遍历才是字典操作的灵魂
前面两篇文章我们学了字典的创建原理和增删改查。今天聚焦字典使用中最频繁的操作——遍历。
增删改查是原子操作,而遍历是批量操作。处理API返回的JSON数据、统计用户行为、构建报表——这些任务都依赖对字典的高效遍历。Python为字典提供了三种视图对象:keys()、values() 和 items(),每种都有独特的用途和技巧。
但遍历不仅仅是 for k, v in d.items() 这一种写法。视图对象的集合特性、遍历中的性能考量、嵌套字典的递归遍历、多字典的并行遍历——这些进阶技巧能让你在处理复杂数据时游刃有余。
二、keys()——键视图
2.1 基本遍历
d = {'name': '小明', 'age': 25, 'city': '北京'}
# 方式一:默认迭代——遍历的是键(最简洁)
for key in d:
print(key)
# name, age, city
# 方式二:显式调用keys()
for key in d.keys():
print(key)
# 同上
# 这两者的效果完全一样
# 但在Python 2中,d.keys()返回的是列表(复制),而默认迭代返回迭代器
# Python 3中d.keys()返回视图对象(动态、不复制)
# 遍历时访问值
for key in d:
print(f'{key} = {d[key]}')
2.2 keys()视图的集合操作
d = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
# keys()支持集合操作!
keys = d.keys()
# 交集
print(keys & {'a', 'c', 'e'}) # {'a', 'c'}
# 并集
print(keys | {'e', 'f'}) # {'a', 'b', 'c', 'd', 'e', 'f'}
# 差集
print(keys - {'a', 'b'}) # {'c', 'd'}
# 对称差
print(keys ^ {'a', 'e'}) # {'b', 'c', 'd', 'e'}
# 成员检查(O(1)!)
print('a' in d.keys()) # True
print('z' in d.keys()) # False
# 实用场景:找出两个字典的公共键
d1 = {'name': '小明', 'age': 25, 'city': '北京'}
d2 = {'name': '小红', 'age': 23, 'job': '设计师'}
common_keys = d1.keys() & d2.keys()
print(common_keys) # {'name', 'age'}
# 找出只在d1中的键
only_in_d1 = d1.keys() - d2.keys()
print(only_in_d1) # {'city'}
# 找出只在一个字典中的键(互斥键)
exclusive = d1.keys() ^ d2.keys()
print(exclusive) # {'city', 'job'}
2.3 keys()视图是动态的
d = {'a': 1, 'b': 2, 'c': 3}
# keys()返回的是视图——能反映字典的实时变化
keys_view = d.keys()
print(list(keys_view)) # ['a', 'b', 'c']
# 修改字典后,视图自动更新
d['d'] = 4
print(list(keys_view)) # ['a', 'b', 'c', 'd']
# 删除后也更新
del d['a']
print(list(keys_view)) # ['b', 'c', 'd']
# ⚠️ 注意:不能在遍历视图时修改字典大小
# for key in d.keys():
# d[f'new_{key}'] = 1 # 可能触发RuntimeError
# 如果需要这样做,先转化为列表
for key in list(d.keys()):
d[f'new_{key}'] = 1
print(d)
# {'b': 2, 'c': 3, 'd': 4, 'new_b': 1, 'new_c': 1, 'new_d': 1}
三、values()——值视图
3.1 基本遍历
d = {'name': '小明', 'age': 25, 'city': '北京'}
# 遍历所有值
for value in d.values():
print(value)
# 小明, 25, 北京
# members检查(O(n)——因为值可能不唯一)
print('小明' in d.values()) # True
print(25 in d.values()) # True
# 值的聚合计算
scores = {'小明': 85, '小红': 92, '小刚': 78, '小李': 95}
# 求和
total = sum(scores.values())
print(f'总分: {total}') # 350
# 平均值
avg = total / len(scores)
print(f'平均分: {avg:.1f}') # 87.5
# 最大最小值
print(f'最高: {max(scores.values())}') # 95
print(f'最低: {min(scores.values())}') # 78
# 值视图也是动态的
values_view = scores.values()
scores['小王'] = 100
print(max(values_view)) # 100(反映了新增的值)
3.2 值视图的限制
# values()视图通常不支持集合操作
# 因为值可能不唯一、可能不可哈希
d = {'a': 1, 'b': 2, 'c': 2, 'd': 3}
# print(d.values() & {1, 2}) # 不一定支持(值可能重复)
# 如果需要值的集合操作,先转为set
unique_values = set(d.values())
print(unique_values & {1, 2}) # {1, 2}
# 成员检查虽然可以用,但需要注意性能
print(2 in d.values()) # True(O(n)检查)
print(2 in d) # True(但这是在检查键!O(1))
# 重要:in d 检查的是键,不是值!
d = {'name': '小明'}
print('name' in d) # True(键存在)
print('小明' in d) # False(这不是键,是值!)
3.3 值视图的应用
# 统计值的分布
scores = {'小明': 85, '小红': 92, '小刚': 78, '小李': 95, '小王': 85, '小张': 92}
# 统计每个分数出现几次
from collections import Counter
score_count = Counter(scores.values())
print(score_count) # Counter({85: 2, 92: 2, 78: 1, 95: 1})
# 找出所有重复的值
duplicated_scores = [score for score, count in score_count.items() if count > 1]
print(f'重复的分数: {duplicated_scores}') # [85, 92]
# 找出得分为85的所有学生
students_with_85 = [name for name, score in scores.items() if score == 85]
print(f'得85分的学生: {students_with_85}') # ['小明', '小王']
四、items()——键值对视图
4.1 基本遍历
d = {'name': '小明', 'age': 25, 'city': '北京'}
# 遍历键值对——最常用的遍历方式
for key, value in d.items():
print(f'{key} = {value}')
# items()返回的是dict_items视图对象
items = d.items()
print(items) # dict_items([('name', '小明'), ('age', 25), ('city', '北京')])
print(type(items)) # <class 'dict_items'>
# items()的元素是元组
for pair in d.items():
print(f'{pair[0]}: {pair[1]}') # 可以但不推荐,用解包更好
# 成员检查(O(1))
print(('name', '小明') in d.items()) # True
print(('name', '小红') in d.items()) # False(值不匹配)
# items视图也是动态的
items_view = d.items()
d['job'] = '工程师'
print(('job', '工程师') in items_view) # True
4.2 items()的集合操作
d1 = {'a': 1, 'b': 2, 'c': 3}
d2 = {'a': 1, 'b': 20, 'd': 4}
# 找出键和值都相同的项
common_items = d1.items() & d2.items()
print(common_items) # {('a', 1)}
# 找出键相同但值不同的项
same_keys_diff_values = {
k: (d1[k], d2[k])
for k in d1.keys() & d2.keys()
if d1[k] != d2[k]
}
print(same_keys_diff_values) # {'b': (2, 20)}
# 找出键值对差异
added = d2.items() - d1.items() # d2中有而d1中没有的
removed = d1.items() - d2.items() # d1中有而d2中没有的
print(f'新增/变化的: {added}') # {('b', 20), ('d', 4)}
print(f'删除/原值: {removed}') # {('c', 3), ('b', 2)}
4.3 items()的排序和过滤
scores = {'小明': 85, '小红': 92, '小刚': 78, '小李': 95, '小王': 88}
# 按键排序
sorted_by_key = dict(sorted(scores.items()))
print(sorted_by_key) # 按姓名排序
# 按值排序
sorted_by_value = dict(sorted(scores.items(), key=lambda x: x[1]))
print(sorted_by_value) # {'小刚': 78, '小明': 85, '小王': 88, '小红': 92, '小李': 95}
# 按值降序
sorted_desc = dict(sorted(scores.items(), key=lambda x: x[1], reverse=True))
print(sorted_desc) # {'小李': 95, '小红': 92, '小王': 88, '小明': 85, '小刚': 78}
# 过滤——找出分数高于85的
high_scores = {k: v for k, v in scores.items() if v > 85}
print(high_scores) # {'小红': 92, '小李': 95, '小王': 88}
# 取前N名
top3 = dict(sorted(scores.items(), key=lambda x: x[1], reverse=True)[:3])
print(f'前三名: {top3}')
五、遍历的高级技巧
5.1 遍历时修改字典
# ⚠️ 黄金法则:不要在遍历字典时修改它的结构(增减键)
# 场景一:需要在遍历时修改值——可以安全进行
prices = {'apple': 10, 'banana': 5, 'orange': 8}
for key in prices:
prices[key] *= 1.1 # 所有价格上涨10%
print(prices) # 安全!只是修改值,没有改变字典结构
# 场景二:需要在遍历时增减键——先收集再操作
d = {'a': 1, 'b': -2, 'c': 3, 'd': -4, 'e': 5}
# 想删除所有负数值
to_delete = [k for k, v in d.items() if v < 0]
for k in to_delete:
del d[k]
print(d) # {'a': 1, 'c': 3, 'e': 5}
# 场景三:同时增加和删除——遍历list(d.keys())的副本
d = {'a': 1, 'b': 2, 'c': 3}
for key in list(d.keys()): # list()创建键的静态快照
if d[key] >= 2:
d[f'big_{key}'] = d.pop(key)
print(d) # {'a': 1, 'big_b': 2, 'big_c': 3}
5.2 嵌套字典遍历
# 两层嵌套字典
school = {
'一年级': {
'一班': 45,
'二班': 42,
'三班': 44,
},
'二年级': {
'一班': 40,
'二班': 43,
},
'三年级': {
'一班': 38,
'二班': 41,
'三班': 39,
},
}
# 遍历嵌套字典
for grade, classes in school.items():
total = sum(classes.values())
print(f'{grade}: 共{len(classes)}个班, {total}人')
for class_name, count in classes.items():
print(f' {class_name}: {count}人')
# 用递归遍历任意深度的嵌套字典
def traverse_dict(d, path=''):
"""递归遍历嵌套字典——打印所有叶子节点"""
for key, value in d.items():
current_path = f'{path}.{key}' if path else key
if isinstance(value, dict):
traverse_dict(value, current_path)
else:
print(f'{current_path} = {value}')
config = {
'app': {
'name': 'MyApp',
'version': '2.0',
'database': {
'host': 'localhost',
'port': 5432,
'pool': {
'min': 5,
'max': 20,
},
},
},
}
traverse_dict(config)
# app.name = MyApp
# app.version = 2.0
# app.database.host = localhost
# app.database.port = 5432
# app.database.pool.min = 5
# app.database.pool.max = 20
5.3 多字典并行遍历
dict1 = {'a': 1, 'b': 2, 'c': 3}
dict2 = {'a': 10, 'b': 20, 'd': 40}
# 并行遍历两个字典的所有键(并集)
all_keys = dict1.keys() | dict2.keys()
for key in all_keys:
val1 = dict1.get(key, 'N/A')
val2 = dict2.get(key, 'N/A')
print(f'{key}: dict1={val1}, dict2={val2}')
# a: dict1=1, dict2=10
# b: dict1=2, dict2=20
# c: dict1=3, dict2=N/A
# d: dict1=N/A, dict2=40
# 只遍历公共键(交集)
common_keys = dict1.keys() & dict2.keys()
for key in common_keys:
print(f'{key}: {dict1[key]} vs {dict2[key]}')
# 比较两个字典
def compare_dicts(d1, d2):
"""详细比较两个字典"""
all_keys = d1.keys() | d2.keys()
only_in_d1 = d1.keys() - d2.keys()
only_in_d2 = d2.keys() - d1.keys()
diff_values = {k: (d1[k], d2[k]) for k in d1.keys() & d2.keys()
if d1[k] != d2[k]}
print(f'只在d1: {only_in_d1}')
print(f'只在d2: {only_in_d2}')
print(f'值不同: {diff_values}')
compare_dicts(dict1, dict2)
六、遍历的性能与实践
6.1 遍历效率对比
import time
d = {f'key_{i}': i for i in range(1000000)}
# 方式一:for key in d(最快——只访问键)
start = time.perf_counter()
for key in d:
_ = key
t1 = time.perf_counter() - start
# 方式二:for key in d.keys()(和方式一几乎一样)
start = time.perf_counter()
for key in d.keys():
_ = key
t2 = time.perf_counter() - start
# 方式三:for key, value in d.items()(最常用)
start = time.perf_counter()
for key, value in d.items():
_ = key, value
t3 = time.perf_counter() - start
# 方式四:for key in d + d[key](两次操作,不推荐)
start = time.perf_counter()
for key in d:
_ = d[key]
t4 = time.perf_counter() - start
print(f'for key in d: {t1:.3f}秒')
print(f'for key in d.keys(): {t2:.3f}秒')
print(f'for k,v in d.items(): {t3:.3f}秒')
print(f'for key in d + d[key]:{t4:.3f}秒')
6.2 最佳实践
# 原则一:需要键时用 for key in d
for key in d: # 最简洁
print(key)
# 原则二:需要值但不需要键时用 for value in d.values()
total = sum(d.values()) # 甚至不需要显式循环
# 原则三:同时需要键和值时用 for k, v in d.items()
for key, value in d.items(): # 清晰且高效
print(f'{key} = {value}')
# 原则四:要修改字典值时可以直接遍历键
for key in d:
d[key] = transform(d[key]) # 安全:只改值,不改结构
# 原则五:要修改字典结构时遍历list(d.keys())
for key in list(d.keys()):
if should_delete(d[key]):
del d[key]
# 原则六:创建新字典比在遍历中修改更安全
filtered = {k: v for k, v in d.items() if condition(v)}
七、实战:数据处理流水线
def analyze_survey(responses):
"""
分析问卷调查结果
输入:[{'name': 'xx', 'age': 25, 'score': 85, 'city': 'Beijing'}, ...]
"""
# 遍历统计
city_counts = {}
age_groups = {'青年(<=30)': 0, '中年(31-50)': 0, '老年(>50)': 0}
total_score = 0
scores_list = []
for r in responses:
# 城市统计
city = r.get('city', '未知')
city_counts[city] = city_counts.get(city, 0) + 1
# 年龄分组
age = r.get('age', 0)
if age <= 30:
age_groups['青年(<=30)'] += 1
elif age <= 50:
age_groups['中年(31-50)'] += 1
else:
age_groups['老年(>50)'] += 1
# 分数统计
score = r.get('score', 0)
total_score += score
scores_list.append(score)
avg_score = total_score / len(responses) if responses else 0
scores_list.sort()
return {
'total': len(responses),
'city_distribution': city_counts,
'age_distribution': age_groups,
'avg_score': round(avg_score, 1),
'median_score': scores_list[len(scores_list) // 2] if scores_list else 0,
'highest_score': scores_list[-1] if scores_list else 0,
'lowest_score': scores_list[0] if scores_list else 0,
}
# 模拟数据
survey_data = [
{'name': '小明', 'age': 25, 'score': 85, 'city': '北京'},
{'name': '小红', 'age': 32, 'score': 92, 'city': '上海'},
{'name': '小刚', 'age': 28, 'score': 78, 'city': '北京'},
{'name': '小李', 'age': 45, 'score': 95, 'city': '广州'},
{'name': '小王', 'age': 55, 'score': 88, 'city': '上海'},
]
result = analyze_survey(survey_data)
for key, value in result.items():
print(f'{key}: {value}')
八、本篇小结
字典的三种视图对象各有其最佳场景:
d.keys():键视图,支持集合操作(交集、并集、差集),成员检查O(1)d.values():值视图,适合聚合运算(sum/max/min),成员检查O(n)d.items():键值对视图,最常用的遍历方式,支持解包和集合操作
关键规则:
- 只遍历键 →
for k in d(不需要显式调用keys()) - 只遍历值 →
for v in d.values() - 同时遍历键和值 →
for k, v in d.items() - 不要在遍历时修改字典结构 → 先收集再操作,或遍历
list(d.keys()) - 视图是动态的 → 会反映字典的实时变化
字典遍历是Python日常编程的基础功。下一篇我们学习字典推导式与字典合并技巧,进一步提升字典操作的效率。
到此这篇关于Python基础指南之字典遍历的核心方法详解的文章就介绍到这了,更多相关Python字典遍历内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
Numpy中np.vstack() 和 np.hstack() 的实现
本文主要介绍了Numpy中np.vstack()和np.hstack()的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧2024-04-04


最新评论