try-except-else-finally
try-except 可以与 else 和 finally 子句组合,形成完整的异常处理结构。每个子句有明确的语义,组合使用可以写出精确的错误处理逻辑。
完整结构
try:
# 可能出错的代码
result = 10 / 2
except ZeroDivisionError:
# 出错时执行
print "Division by zero"
else:
# 没有异常时执行
print "Result:", result
finally:
# 无论是否异常都执行
print "Cleanup"
# 输出:
# Result: 5.0
# Cleanup
else 子句
else 块在 try 块没有抛出异常时执行。它的用途是把"正常逻辑"和"错误处理"分离:
try:
data = fetch_data()
except NetworkError:
print "Network failed"
else:
# 只有 fetch_data() 成功时才执行
process(data)
save(data)
如果把 process(data) 放在 try 块中,它抛出的异常会被 except NetworkError 捕获——这可能不是想要的:
try:
data = fetch_data()
process(data) # 如果这里出错,会被 except 捕获
save(data)
except NetworkError:
# 可能捕获了 process() 或 save() 的错误,误以为是网络问题
print "Network failed"
else 让 except 只捕获 fetch_data() 的异常,后续操作有自己的错误处理。
finally 子句
finally 块无论是否发生异常都会执行,常用于资源清理:
f = open("data.txt", "r")
try:
data = f.read()
process(data)
except IOError:
print "Read failed"
finally:
f.close() # 无论是否异常,文件都会关闭
print "File closed"
finally 在以下情况都会执行:
try正常完成try发生异常并被except捕获try发生异常但未被捕获try或except中有return、break、continue
def test():
try:
return "try"
finally:
print "finally" # 会在 return 之前执行!
print test()
# 输出:
# finally
# try
finally 中的代码甚至在 return 之后执行。如果 finally 中也有 return,它会覆盖 try 中的返回值:
def test():
try:
return "try"
finally:
return "finally" # 覆盖 try 的返回值!
print test() # finally
组合使用
try:
conn = create_connection()
data = conn.fetch()
except ConnectionError:
print "Connection failed"
return None
else:
result = process(data)
return result
finally:
conn.close() # 无论成功失败,连接都关闭
与 with 语句的对比
with 语句是 try-finally 的语法糖,用于上下文管理:
# try-finally 写法
f = open("data.txt", "r")
try:
data = f.read()
finally:
f.close()
# with 写法(等价但更简洁)
with open("data.txt", "r") as f:
data = f.read()
对于文件、锁、数据库连接等资源,with 是首选。对于复杂的清理逻辑,try-finally 更灵活。
实际应用
事务处理:
try:
db.begin()
update_account(from_acc, -amount)
update_account(to_acc, amount)
db.commit()
except TransactionError:
db.rollback()
print "Transaction failed"
else:
print "Transaction completed"
finally:
db.close()
临时状态恢复:
old_value = config.debug
try:
config.debug = True
run_tests()
finally:
config.debug = old_value # 无论测试是否通过,恢复配置
执行顺序总结
| 情况 | 执行顺序 |
|---|---|
| 无异常 | try → else → finally |
| 有异常,被捕获 | try(到异常点)→ except → finally |
| 有异常,未捕获 | try(到异常点)→ finally → 异常传播 |
| try 中有 return | try(到 return)→ finally → return |
| except 中有 return | try → except(到 return)→ finally → return |