try-except写得太粗什么异常都catch了——异常处理最佳实践
先说结论
核心原则:catch具体异常、不except pass、记录异常、区分可恢复和不可恢复。ETL策略:脏数据try-except跳过+计数+记录;网络错误重试;配置错误直接崩;资源用with管理。
先把这段讲顺;面试官追问时,再展开下面的原理和细节。
详细讲解
常见反模式和正确写法
# 反模式:except pass
try: data = process(row)
except Exception: pass # 数据丢了不知道!
# 正确:catch具体异常+记录+计数
for row in rows:
try: data = process(row)
except (ValueError, KeyError) as e:
error_count += 1
logging.warning(f'Skip: {e}')
if error_count > len(rows) * 0.01:
raise RuntimeError(f'Too many errors: {error_count}')
ETL异常策略
| 类型 | 策略 | 做法 | 示例 |
|---|---|---|---|
| 数据质量 | 跳过+记录 | try-except | null/格式错误 |
| 网络故障 | 重试 | @retry | API超时 |
| 配置错误 | 直接崩 | 不catch | 路径/密码错 |
| 资源管理 | finally释放 | with语句 | 数据库连接 |
# 完整ETL异常模板
def run_etl():
error_rows = []; total = 0
try:
conn = get_connection() # 配置错直接崩
df = load_data(conn)
for idx, row in df.iterrows():
total += 1
try:
save(transform(row))
except (ValueError, KeyError) as e:
error_rows.append((idx, str(e)))
if len(error_rows)/max(total,1) > 0.01:
send_alert(f'{len(error_rows)} errors in {total} rows')
except Exception as e:
logging.error(f'ETL failed: {e}', exc_info=True)
raise # 让调度系统知道失败
自定义异常
class DataQualityError(Exception): pass
class RetryableError(Exception): pass
try: validate(row)
except DataQualityError: skip_and_log(row)
except RetryableError: retry_later(row)
实战踩坑:except pass导致数据少30%
某短剧出海公司,上游日期格式变了,所有日期解析ValueError被pass掉。脚本'成功'完成但30%数据被静默跳过。运营两天后才发现报表数字不对。
修复:① except pass改成log+计数;② 异常率超1%发飞书告警;③ 每天自动比对输入输出行数差距超5%告警。
面试高频追问
追问一:else和finally?
else在try没异常时执行。finally无论如何都执行(甚至return前也执行)。
追问二:raise from?
设置异常链。raise NewError() from original保留原因链方便排查。
追问三:logging.exception()?
自动附加traceback。在except块里推荐用logging.exception()而不是logging.error()。
总结
异常处理讲三层:① catch具体异常不要pass;② ETL策略(脏数据跳过+网络重试+配置直接崩);③ except pass最危险(脚本'成功'但数据错几天才发现)。能讲出30%数据丢失的踩坑,面试官觉得你有代码质量意识。
下一篇聊Airflow DAG为什么用Python写——元编程基础。
你们ETL异常处理策略是什么?评论区聊聊~
关注「Wood聊大数据」| 9年大数据老兵,只讲大数据面试干货
Python 面试通关手册
第16-20篇:进阶特性与面试总结
Wood聊大数据
9年大数据老兵,只讲大数据面试干货