
本文介绍如何使用python的csv.dictreader流式读取tsv文件,避免内存占用过高,同时解决“_csv.reader对象不可索引”错误,正确计算用户年龄中位数。
在处理大型CSV/TSV文件时,为节省内存,我们通常希望逐行读取、即时计算,而非一次性加载全部数据(如pandas.read_csv()或list(csv.reader()))。但初学者常误用csv.reader——它返回的是按列索引的列表(如row[2]),而代码中却尝试像字典一样用键名访问(如row['birth_year']),从而触发 TypeError: '_csv.reader' object is not subscriptable 错误。
根本原因在于:csv.reader 生成的每一行是 list 类型(例如 ['paul', 'henry', '2019']),不支持 row['birth_year'] 这种键访问;而 csv.DictReader 才会将首行自动解析为字段名,并为后续每行返回一个 dict(如 {'first': 'paul', 'last': 'henry', 'birth_year': '2019'}),真正支持键值访问。
✅ 正确做法是改用 csv.DictReader,并配合生成器表达式实现内存友好的流式计算:
import csv
from statistics import median
def median_age(filename):
with open(filename, 'r', encoding='utf-8') as file:
reader = csv.DictReader(file, delimiter='\t')
# 使用生成器:逐行读取,即时计算年龄,不构建完整列表
ages = (2024 - int(row['birth_year']) for row in reader)
return median(ages)? 关键要点说明:
- ✅ csv.DictReader 自动将第一行作为字段名(header),无需手动跳过(next(reader) 不再需要);
- ✅ 生成器 (2024 - int(...)) for row in reader 不会缓存所有年龄值,仅维持迭代状态,内存占用恒定(O(1));
- ✅ 建议显式指定 encoding='utf-8' 避免中文或特殊字符报错;
- ⚠️ 确保输入文件中存在名为 'birth_year' 的列(大小写敏感),否则抛出 KeyError;可添加异常处理增强鲁棒性:
# 可选:增加字段校验与容错
if 'birth_year' not in reader.fieldnames:
raise ValueError(f"Column 'birth_year' not found in header: {reader.fieldnames}")? 示例运行(以制表符分隔的 data.csv):
first last birth_year paul henry 2019 bill thompson 1995 mary allen 2003 jennifer davis 2015 liz morgan 1999
调用 median_age('data.csv') 将依次计算年龄 [5, 29, 21, 9, 25],中位数为 21(已排序后取中间值)。
总结:流式处理大数据CSV的核心是「用对工具」——DictReader 提供语义化访问,生成器确保低内存开销,二者结合即可安全、高效、可维护地完成年龄统计任务。










