Python字典遍历核心方法:keys/values/items视图及最佳实践
在Python日常编程中,字典的遍历是最频繁的操作之一。无论是处理API返回的JSON数据、统计用户行为还是构建报表,高效遍历字典都是基本功。Python 3为字典提供了三种视图对象:keys()、values()和items(),每种都有独特的用途和技巧。本文将从基本遍历出发,深入探讨视图的动态性、集合操作、高级遍历技巧以及性能对比,最后通过一个实战案例展示完整的数据处理流水线。d = {'name': '小明', 'age': 25, 'city': '北京'}
# 默认迭代遍历的是键,最简洁
for key in d:
print(key)
# 显式调用keys()效果相同
for key in d.keys():
print(key)
# 遍历时访问值
for key in d:
print(f'{key} = {d}')
keys()视图支持集合操作,例如交集、并集、差集和对称差。利用d1.keys() & d2.keys()可以快速找出两个字典的公共键。
d1 = {'name': '小明', 'age': 25, 'city': '北京'}
d2 = {'name': '小红', 'age': 23, 'job': '设计师'}
common_keys = d1.keys() & d2.keys()
print(common_keys)# {'name', 'age'}
keys()视图是动态的,修改字典后视图自动更新。但注意不能在遍历视图时修改字典大小(增减键),否则可能触发RuntimeError。如果需要边遍历边修改,应先将键转化为列表。
d = {'a': 1, 'b': 2, 'c': 3}
for key in list(d.keys()):
d = 1
print(d)# 安全修改
values()视图适合做值的聚合计算,例如求和、平均值、最大最小值。成员检查是O(n)的,因为值可能重复。
scores = {'小明': 85, '小红': 92, '小刚': 78, '小李': 95}
total = sum(scores.values())
print(total)# 350
avg = total / len(scores)
print(avg)# 87.5
values()视图通常不支持集合操作,因为值可能不可哈希或重复。需要集合操作时可以先转为set。注意in d检查的是键而不是值,容易混淆。
items()视图是最常用的遍历方式,同时获取键和值。它也支持集合操作,可以用&找出两个字典中键值完全相同的项。还可以结合sorted()实现按键或按值排序。
scores = {'小明': 85, '小红': 92, '小刚': 78, '小李': 95, '小王': 88}
# 按值升序
sorted_by_value = dict(sorted(scores.items(), key=lambda x: x))
# 按值降序取前三
top3 = dict(sorted(scores.items(), key=lambda x: x, reverse=True)[:3])
高级技巧方面,第一个黄金法则:不要在遍历字典时修改其结构(增减键)。如果只需要修改值,可以直接遍历键并修改d。如果需要增删键,先收集到列表再操作,或者遍历list(d.keys())创建快照。
嵌套字典可以用递归遍历。
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}')
多字典并行遍历时,可以利用keys()视图的并集或交集。
性能对比测试(100万条数据)表明,for key in d和for key in d.keys()几乎一样快,for k,v in d.items()稍慢但更常用,for key in d + d最慢,因为两次哈希操作。
import time
d = {f'key_{i}': i for i in range(1000000)}
start = time.perf_counter()
for key in d:
_ = key
t1 = time.perf_counter() - start
# 其他方式类似
最佳实践原则:
- 只需要键:for key in d
- 只需要值:for v in d.values(),甚至可以用sum(d.values())等聚合函数
- 同时需要键和值:for k, v in d.items()
- 要修改字典值:直接遍历键并赋值
- 要修改字典结构:遍历list(d.keys())或列表推导式收集后再操作
实战:问卷调查结果分析。
def analyze_survey(responses):
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_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 if scores_list else 0,
'highest_score': scores_list[-1] if scores_list else 0,
'lowest_score': scores_list 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}')
总结:keys()视图支持集合操作且动态,适合键的批量处理;values()适合值的聚合计算;items()是遍历的主力。牢记不要在遍历时修改字典结构,善用视图的动态性和集合操作,能极大提升代码效率。
Re: Python字典遍历核心方法:keys/values/items视图及最佳实践
楼主总结得真全面!keys/values/items 这三种视图的动态性确实是 Python 3 的亮点,特别是 keys() 支持集合操作在生产中很实用,比如对比两个配置字典的差异。 我补充一点:在实战代码那里有个小疏忽——`city_counts = city_counts.get(city, 0) + 1` 这行每次都会把字典重新赋值为一个整数,导致后续 `city_counts` 会报错。应该改成 `city_counts = city_counts.get(city, 0) + 1` 或者用 `defaultdict(int)`。另外 Python 3.7+ 的字典已经保持插入顺序,遍历时按键顺序稳定的特性也可以利用一下,比如用 `dict.fromkeys` 保留顺序去重。感谢楼主分享!Re: Python字典遍历核心方法:keys/values/items视图及最佳实践
感谢楼主分享,内容非常全面!特别是关于视图动态性和“遍历时不能增减键”的提醒,这个坑我之前踩过,后来才学会用 `list(d.keys())` 做快照。实战案例分析也很实用,直接照着改改就能用了。另外想请教一下,如果嵌套字典很深且不确定层数,递归遍历时有没有更好的办法避免递归深度限制?Re: Python字典遍历核心方法:keys/values/items视图及最佳实践
学到了很多,感谢分享!特别是keys()视图支持集合操作这个技巧很实用,之前没想到可以直接用`&`找公共键,省去循环判断的麻烦。 另外想确认一下,实战例子里的`city_counts = city_counts.get(city, 0) + 1`是不是应该写成`city_counts = city_counts.get(city, 0) + 1`?否则`city_counts`好像没被正确更新。可能是个小笔误,但整体思路非常清晰。
页:
[1]