Python 中 try / except / else / finally 异常处理详解
情况tryexceptelsefinally没有异常执行跳过执行执行有异常,匹配到执行到异常处中断执行跳过执行有异常,未匹配到执行到异常处中断不执行不执行执行(然后异常继续向上抛出)try:放可能出错的代码except:出错就处理else:没出错才执行finally:一定会执行passraise DataFormatError("数据必须是字典类型")try:print("捕获到自定义异常:",
1. 基本结构
try:
# 可能会抛出异常的代码
except SomeException as e:
# 捕获并处理异常
else:
# 如果 try 中代码没有异常,就执行这里
finally:
# 无论是否发生异常,最后都会执行这里
2. 各部分的作用
try
- 用途:包含可能发生异常的代码段。
- 如果代码没有异常,则
except
不会被执行,直接进入else
(如果有的话)。 - 如果有异常,则转到对应的
except
。
except
- 用途:捕获并处理异常。
- 可以写多个
except
,匹配不同的异常类型。
示例:
try:
x = int("abc") # 会触发 ValueError
except ValueError:
print("捕获到 ValueError")
except TypeError:
print("捕获到 TypeError")
else
- 用途:只有当 try 中没有发生任何异常时 才会执行。
- 常用于把 不需要异常保护的逻辑 放在这里,让
try
中的代码尽量简洁。
示例:
try:
result = 10 / 2
except ZeroDivisionError:
print("除零错误")
else:
print("计算成功,结果是:", result)
运行结果:
计算成功,结果是: 5.0
finally
- 用途:无论是否发生异常,都会执行。
- 常用于资源释放、文件关闭、锁释放等。
示例:
try:
f = open("test.txt", "r")
data = f.read()
except FileNotFoundError:
print("文件不存在")
else:
print("读取成功")
finally:
print("执行 finally")
if 'f' in locals() and not f.closed:
f.close()
3. 执行流程总结
情况 | try |
except |
else |
finally |
---|---|---|---|---|
没有异常 | 执行 | 跳过 | 执行 | 执行 |
有异常,匹配到 | 执行到异常处中断 | 执行 | 跳过 | 执行 |
有异常,未匹配到 | 执行到异常处中断 | 不执行 | 不执行 | 执行(然后异常继续向上抛出) |
4. 常见用法
(1)多个 except
try:
x = int("abc")
except ValueError:
print("数值错误")
except Exception as e:
print("其他异常:", e)
(2)捕获多个异常
try:
x = int("abc")
except (ValueError, TypeError) as e:
print("捕获到异常:", e)
(3)用 else
处理后续逻辑
try:
num = int("123")
except ValueError:
print("转换失败")
else:
print("转换成功,结果是:", num)
(4)finally
释放资源
try:
f = open("data.txt", "r")
data = f.read()
except FileNotFoundError:
print("文件没找到")
finally:
print("关闭文件")
if 'f' in locals() and not f.closed:
f.close()
5. 容易踩的坑
finally
中的 return 会覆盖异常
def foo():
try:
return 1
finally:
return 2
print(foo()) # 输出 2,而不是 1
说明:finally
里的 return
、break
、continue
都会覆盖 try/except/else
的返回值或异常。
-
过度使用
try
- 最佳实践:只把 可能发生异常的最小代码块 放进
try
,不要把一大段逻辑全包进去。
- 最佳实践:只把 可能发生异常的最小代码块 放进
6.常用场景示例
下面 6 个示例覆盖了:
- 文件操作
- 用户输入
- 网络请求
- 多异常捕获
- 数据库操作
- 临时文件清理
示例 1:文件读取(带 finally
关闭资源)
try:
f = open("test.txt", "r")
data = f.read()
except FileNotFoundError:
print("文件不存在")
else:
print("文件内容:", data)
finally:
if 'f' in locals() and not f.closed:
f.close()
print("文件已关闭")
应用场景:文件操作时,确保资源一定会被关闭。
示例 2:用户输入校验
try:
num = int(input("请输入一个整数: "))
except ValueError:
print("输入无效,请输入整数!")
else:
print("你输入的整数是:", num)
应用场景:处理用户输入时防止格式错误。
示例 3:网络请求(简化版)
import requests
try:
response = requests.get("https://httpbin.org/get")
data = response.json()
except requests.RequestException as e:
print("请求失败:", e)
else:
print("请求成功,返回数据:", data)
finally:
print("请求结束")
应用场景:网络请求一定要有异常处理,否则一旦超时或断网就会崩溃。
示例 4:多个异常捕获
try:
x = int("abc") # ValueError
y = 10 / 0 # ZeroDivisionError
except ValueError:
print("数值转换错误")
except ZeroDivisionError:
print("除零错误")
except Exception as e:
print("其他错误:", e)
应用场景:针对不同错误分类处理,更清晰。
示例 5:数据库操作(带 finally
释放连接)
class FakeDB:
def connect(self): print("连接数据库")
def close(self): print("关闭数据库")
def query(self): return [1, 2, 3]
db = FakeDB()
try:
db.connect()
result = db.query()
except Exception as e:
print("查询失败:", e)
else:
print("查询结果:", result)
finally:
db.close()
应用场景:数据库、消息队列、Socket等操作中保证资源一定释放。
示例 6:finally
保证清理临时文件
import os
try:
with open("temp.txt", "w") as f:
f.write("临时数据")
raise RuntimeError("模拟出错")
except RuntimeError as e:
print("捕获到异常:", e)
finally:
if os.path.exists("temp.txt"):
os.remove("temp.txt")
print("临时文件已删除")
应用场景:程序中断时确保临时文件、缓存不会遗留。
7. 总结口诀
try
:放可能出错的代码except
:出错就处理else
:没出错才执行finally
:一定会执行
高级应用内容
高级应用主要涉及:
- 异常链:处理后再抛出
- 自定义异常:模块化项目常用
- 上下文管理器:优雅封装
try/finally
- 逻辑分层:
else
只放成功逻辑 - finally 覆盖陷阱:调试必知
- contextlib.suppress:优雅忽略异常
- 事务回滚:数据库/分布式系统
- 多线程异常处理:防止异常丢失
下面分别举例说明,具体内容如下:
1. 捕获并重新抛出异常(异常链)
有时需要先处理一下,再把异常继续抛给上层:
def process_data(data):
try:
return int(data)
except ValueError as e:
print("日志记录:数据转换失败 ->", e)
raise # 重新抛出异常,让上层调用者知道
应用场景:日志记录、错误追踪。
2. 自定义异常类
在工程里,为了更清晰区分错误类型,常会定义自家异常:
class DataFormatError(Exception):
pass
def load_data(data):
if not isinstance(data, dict):
raise DataFormatError("数据必须是字典类型")
try:
load_data("not_dict")
except DataFormatError as e:
print("捕获到自定义异常:", e)
应用场景:大型项目中,给模块定义专属错误类型,便于精确捕获。
3. with
上下文管理器的异常处理
上下文管理器的 __exit__
方法可以接收异常,并决定是否吞掉:
class Demo:
def __enter__(self):
print("进入上下文")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print("退出上下文")
if exc_type:
print("捕获异常:", exc_type, exc_val)
return True # 返回 True 表示异常已处理,不会再抛出
with Demo():
print("运行中...")
raise ValueError("测试异常")
print("程序继续执行")
应用场景:数据库事务、文件操作、锁等,结合 try/finally
自动化资源管理。
4. try/except/else
结合逻辑分层
让 try
只负责可能出错的部分,后续逻辑放到 else
,保持结构清晰:
try:
f = open("config.json")
config = f.read()
except FileNotFoundError:
print("配置文件缺失")
else:
print("配置文件加载成功")
finally:
if 'f' in locals():
f.close()
应用场景:避免把无关代码放进 try
,提高可读性。
5. finally
中的清理 vs. 异常屏蔽
注意:如果 finally
里有 return/raise
,会覆盖原异常:
def test():
try:
1 / 0
except ZeroDivisionError:
print("捕获到异常")
raise
finally:
return "finally 覆盖了异常"
print(test()) # 输出 "finally 覆盖了异常"
应用场景:调试时要小心,避免无意中吞掉异常。
6. contextlib.suppress
—— 优雅忽略异常
Python 内置的工具类,可以用来代替 try/except/pass
:
import contextlib
with contextlib.suppress(FileNotFoundError):
with open("no_such_file.txt") as f:
data = f.read()
print("即使文件不存在,程序也能继续运行")
应用场景:当你明确不关心某些异常时,代码更简洁。
7. 异常和事务(数据库/分布式)
很多数据库驱动会在 try/except/finally
中实现事务控制:
try:
db.begin()
db.insert("users", {"id": 1, "name": "Alice"})
db.commit()
except Exception as e:
db.rollback()
print("事务失败:", e)
应用场景:保证数据一致性。
8. 异常与多线程
在多线程中,子线程的异常不会自动传递到主线程,需要显式捕获:
import threading
def worker():
try:
1 / 0
except Exception as e:
print("子线程异常:", e)
t = threading.Thread(target=worker)
t.start()
t.join()
应用场景:多线程/异步编程中异常管理。
更多推荐
所有评论(0)