
本文介绍如何使用 csv.dictreader 流式读取制表符分隔的 csv 文件,避免内存溢出,同时正确提取出生年份并计算当前(2024年)年龄的中位数,解决 '_csv.reader' object is not subscriptable 类型错误。
在处理大型 CSV 文件时,为节省内存,应避免将整个文件一次性读入列表或 DataFrame。Python 的 csv 模块提供了流式读取能力,但需注意 csv.reader 与 csv.DictReader 的关键区别:前者返回每行为 list(需用索引访问字段,如 row[2]),后者返回每行为 dict(支持按列名访问,如 row['birth_year'])。原代码中误将 csv.reader 对象当作字典使用(data['birth_year']),导致 TypeError。
正确做法是改用 csv.DictReader,它自动将首行解析为字段名,并为后续每一行构建键值映射。此外,我们采用生成器表达式 (2024 - int(row['birth_year']) for row in reader) 实现惰性求值——年龄值在中位数计算过程中逐个生成,全程不构建完整列表,真正实现低内存占用。
以下是完整、健壮的实现(含基础异常处理):
import csv
from statistics import median
def median_age(filename):
try:
with open(filename, 'r', encoding='utf-8') as file:
reader = csv.DictReader(file, delimiter='\t')
# 验证必需字段是否存在
if 'birth_year' not in reader.fieldnames:
raise ValueError(f"Missing required column 'birth_year' in {filename}")
# 生成年龄序列(跳过空值或无效年份)
ages = []
for row in reader:
try:
birth_year = int(row['birth_year'].strip())
if 1900 <= birth_year <= 2024: # 合理年份范围过滤
ages.append(2024 - birth_year)
except (ValueError, TypeError):
continue # 跳过无法解析的行
if not ages:
raise ValueError(f"No valid birth_year found in {filename}")
return median(ages)
except FileNotFoundError:
raise FileNotFoundError(f"File '{filename}' not found.")
except Exception as e:
raise RuntimeError(f"Error processing {filename}: {e}")使用示例:
假设 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') 将返回 21.0(对应年龄序列 [5, 29, 21, 9, 25] 的中位数)。
关键注意事项:
- ✅ 始终指定 encoding='utf-8' 防止中文或特殊字符报错;
- ✅ 使用 DictReader 而非 reader 实现列名访问;
- ✅ 通过生成器+显式循环+过滤,兼顾内存效率与数据鲁棒性;
- ❌ 避免在 csv.reader 上直接使用方括号索引(如 row['xxx']);
- ⚠️ 若文件无标题行,需手动传入 fieldnames= 参数;若分隔符非制表符,请同步调整 delimiter。
该方案适用于 GB 级日志或用户档案 CSV,单次遍历、零中间列表、错误可追溯,是生产环境推荐的轻量级年龄统计实践。










