在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[key]}')
复制代码
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[f'new_{key}'] = 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[1]))
- # 按值降序取前三
- top3 = dict(sorted(scores.items(), key=lambda x: x[1], reverse=True)[:3])
复制代码
高级技巧方面,第一个黄金法则:不要在遍历字典时修改其结构(增减键)。如果只需要修改值,可以直接遍历键并修改d[key]。如果需要增删键,先收集到列表再操作,或者遍历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[key]最慢,因为两次哈希操作。
- 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] = 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}')
复制代码
总结:keys()视图支持集合操作且动态,适合键的批量处理;values()适合值的聚合计算;items()是遍历的主力。牢记不要在遍历时修改字典结构,善用视图的动态性和集合操作,能极大提升代码效率。 |