Python zip()创建字典仅含2条记录而非千余条的问题排查
列表zip转字典仅返回2条记录的异常排查与修复
问题场景
完成Codecademy平台美国医疗保险成本组合项目时,创建smoking_status、insurance_costs两个列表存储CSV中读取的吸烟状态、保险成本字段,用于分析两类人群的成本差异。通过zip()打包两个列表、用字典推导式生成字典时,最终输出仅包含2个键值对,对应CSV文件最后两条数据,未得到预期的1000余条记录。
涉及的原始代码:
import csv insurance_db = with open('insurance.csv',newline='') as insurance_csv: insurance_reader = csv.DictReader(insurance_csv) for row in insurance_reader: insurance_db.append(row) smoking_status = [] for person in insurance_db: smoking_status.append(person.get('smoker')) insurance_costs = [] for person in insurance_db: insurance_costs.append(person.get('charges')) smoker_dictionary = {key:value for key,value in zip(smoking_status,insurance_costs)} print(smoker_dictionary)
实际运行输出:
{'yes': '29141.3603', 'no': '2007.945'}
异常成因
核心原因是Python字典的键具有全局唯一性,同键重复赋值时新值会直接覆盖旧值:
smoking_status列表的取值只有'yes'、'no'两类,不存在其他值- 字典推导式遍历zip生成的键值对时,每遍历到一条吸烟状态为
'yes'的记录,就会覆盖字典中已有的'yes'键对应的值;'no'键同理 - 遍历完全部1000余条记录后,两个键各自仅保留最后一次被赋值的内容,正好对应CSV文件末尾两条记录的数值。
另外原始代码存在显性语法问题:insurance_db =后未初始化空列表,运行时会直接触发NameError,需要补全为insurance_db = []。
修复方案
根据实际业务需求选择对应写法即可:
- 需求1:按吸烟状态分组,统计两类人群的成本特征(如平均成本、成本区间)
不要直接用吸烟状态作为单值键,改为将同状态的所有成本存入键对应的列表中,参考代码:import csv insurance_db = [] with open('insurance.csv', newline='') as insurance_csv: insurance_reader = csv.DictReader(insurance_csv) for row in insurance_reader: insurance_db.append(row) # 初始化分组字典,键为吸烟状态,值为对应人群的所有成本 smoker_cost_dict = {'yes': [], 'no': []} for person in insurance_db: smoker_status = person.get('smoker') # 把成本转成浮点数,方便后续做数值计算 charge = float(person.get('charges')) smoker_cost_dict[smoker_status].append(charge) # 后续可直接做统计计算,比如计算两类人群的平均保险成本 avg_smoker_cost = sum(smoker_cost_dict['yes']) / len(smoker_cost_dict['yes']) avg_non_smoker_cost = sum(smoker_cost_dict['no']) / len(smoker_cost_dict['no']) - 需求2:存储所有记录的映射关系
不要用重复度极高的吸烟状态作为字典键,改用每条记录的唯一标识(如记录序号、用户ID)作为键,值存储包含吸烟状态、保险成本的结构化数据,避免键重复覆盖。
原始字典推导式的逻辑等价于逐行给字典同键重复赋值,执行过程可以通过以下代码直观复现:
test_dict = {} # 模拟遍历前1000条重复yes/no的记录 for i in range(1000): if i % 2 == 0: test_dict['yes'] = i else: test_dict['no'] = i # 最终输出只会保留最后一次赋值的998、999两个值 print(test_dict)
内容的提问来源于stack exchange,提问作者Brian Faxon
相关产品推荐
相关产品推荐

