如何用Python导入CSV文件并避免‘已关闭文件上的I/O操作’错误
问题分析与解决方案
核心错误原因
你遇到的I/O operation on closed file.错误,是因为with语句块执行结束后,会自动关闭关联的文件对象insurance_data,此时在块外调用函数访问该文件对象,自然会触发已关闭文件的I/O操作错误。此外,你的函数代码还存在语法、数据类型处理的问题,需要一并修正。
修正方案一:在with块内完成统计
将函数定义和调用都放在with块内部,确保文件处于打开状态时完成数据遍历:
import csv with open("insurance.csv", newline="") as insurance_data: insurance_reader = csv.DictReader(insurance_data) def bmi_categories(reader): obese_counter = 0 overweight_counter = 0 # 遍历每一条记录 for item in reader: # 将CSV中读取的字符串类型BMI转为数值型 bmi = float(item["BMI"]) if 25 < bmi <= 30: overweight_counter += 1 elif bmi > 30: obese_counter += 1 # 返回统计结果 return {"超重人数": overweight_counter, "肥胖人数": obese_counter} # 调用函数并打印结果 stat_result = bmi_categories(insurance_reader) print(f"统计结果:{stat_result}")
修正方案二:先缓存数据再统计
如果需要在with块外处理数据,可以先把所有记录读取到列表中,文件关闭后依然能使用缓存的数据:
import csv # 先读取所有数据到列表,缓存下来 insurance_records = [] with open("insurance.csv", newline="") as insurance_data: insurance_reader = csv.DictReader(insurance_data) insurance_records = list(insurance_reader) def bmi_categories(records): obese_counter = 0 overweight_counter = 0 for item in records: bmi = float(item["BMI"]) if 25 < bmi <= 30: overweight_counter += 1 elif bmi > 30: obese_counter += 1 return {"超重人数": overweight_counter, "肥胖人数": obese_counter} # 调用函数并输出结果 stat_result = bmi_categories(insurance_records) print(f"统计结果:{stat_result}")
关键修正点说明
- 文件生命周期问题:
with块的设计就是自动管理文件开闭,所以要么在块内完成所有文件操作,要么提前将数据缓存到内存对象(比如列表)中。 - 语法与数据类型:
- 原代码
for item[BMI] in file是错误语法,应改为遍历每条记录item,再通过字符串键item["BMI"]取值。 - CSV读取的所有字段都是字符串类型,必须用
float()转换为数值后才能进行大小比较。
- 原代码
- 结果返回:让函数返回统计结果字典,方便后续查看或进一步处理。
内容的提问来源于stack exchange,提问作者Matthew Christie
相关产品推荐
相关产品推荐

