文章目录
各位老板好
,在Python中,异常是程序执行过程中发生的一个事件,该事件会打断正常的程序流程。当Python脚本遇到一个无法处理的情况时,就会引发一个异常。异常是一个Python对象,它表示一个错误。
通过异常处理,我们可以优雅地处理错误,而不是让整个程序崩溃。它允许我们在程序出错时执行特定的代码,比如清理资源、记录日志或者给用户一个友好的错误提示。
1 底层原理
异常处理机制的核心流程:
- 触发异常:当解释器检测到错误时,会创建异常对象并中断当前流程
- 查找处理程序:从当前栈帧开始向上回溯调用栈
- 匹配处理程序:检查
except
子句是否能捕获该异常类型 - 执行处理:执行匹配的
except
块中的代码 - 资源清理:无论是否发生异常都执行
finally
块 - 继续执行:处理完成后继续执行后续代码或终止程序
import sys
def func1():
raise ValueError("核心错误")
def func2():
try:
func1()
except TypeError:
print("类型错误捕获")
try:
func2()
except ValueError as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
print(f"异常类型: {exc_type}")
print(f"异常对象: {exc_obj}")
print(f"追踪对象: {exc_tb.tb_lineno}")
2 基础用法
2.1 基本异常捕获
try:
# 可能出错的代码
result = 10 / 0
except ZeroDivisionError:
# 特定异常处理
print("除数不能为零!")
except (TypeError, ValueError) as e:
# 多异常捕获
print(f"类型或数值错误: {e}")
except Exception as e:
# 通用异常捕获
print(f"未知错误: {e}")
else:
# 无异常时执行
print("计算成功!")
finally:
# 始终执行
print("清理资源...")
2.2 手动抛出异常
def process_age(age):
if age < 0:
raise ValueError("年龄不能为负")
elif age > 150:
raise ValueError("年龄超过合理范围")
return f"年龄: {age}"
try:
print(process_age(-5))
except ValueError as ve:
print(f"输入错误: {ve}")
2.3 异常链
try:
try:
import non_existent_module
except ImportError as ie:
raise RuntimeError("模块加载失败") from ie
except RuntimeError as re:
print(f"主错误: {re}")
print(f"原始错误: {re.__cause__}")
3 进阶用法
3.1 自定义异常
class NetworkTimeoutError(Exception):
"""自定义网络超时异常"""
def __init__(self, message, host, port):
super().__init__(message)
self.host = host
self.port = port
def __str__(self):
return f"{self.args[0]} @ {self.host}:{self.port}"
def connect_server():
# 模拟连接失败
raise NetworkTimeoutError("连接超时", "api.example.com", 8080)
try:
connect_server()
except NetworkTimeoutError as ne:
print(f"错误代码: {ne}")
print(f"主机: {ne.host}, 端口: {ne.port}")
3.2 上下文管理器异常处理
class DatabaseConnection:
def __enter__(self):
print("建立数据库连接")
return self
def execute(self, query):
if "DROP" in query:
raise PermissionError("禁止执行危险操作")
print(f"执行: {query}")
def __exit__(self, exc_type, exc_val, exc_tb):
print("关闭数据库连接")
if exc_type:
print(f"操作出错: {exc_val}")
return True # 抑制异常传播
with DatabaseConnection() as db:
db.execute("SELECT * FROM users")
db.execute("DROP TABLE users") # 触发异常但被抑制
print("程序继续运行")
3.3 异常装饰器
def retry_on_failure(max_retries=3):
def decorator(func):
def wrapper(*args, **kwargs):
for attempt in range(1, max_retries+1):
try:
return func(*args, **kwargs)
except ConnectionError as ce:
print(f"尝试 {attempt}/{max_retries} 失败: {ce}")
if attempt == max_retries:
raise RuntimeError("所有重试失败") from ce
return None
return wrapper
return decorator
@retry_on_failure(max_retries=2)
def fetch_data():
print("尝试获取数据...")
raise ConnectionError("网络中断")
fetch_data()
3.4 异常性能优化技巧
# 反模式:使用异常处理控制流
def find_index_bad(items, target):
try:
return items.index(target)
except ValueError:
return -1
# 优化方案:条件判断代替异常
def find_index_good(items, target):
if target in items:
return items.index(target)
return -1
# 性能对比
import timeit
setup = "items = list(range(1000)); target = 2000"
print("异常方式耗时:",
timeit.timeit('find_index_bad(items, target)', setup=setup, globals=globals()))
print("条件判断耗时:",
timeit.timeit('find_index_good(items, target)', setup=setup, globals=globals()))
4 最佳实践原则
- 精确捕获:避免空
except:
或捕获过于宽泛的异常 - 异常文档化:在函数文档中说明可能抛出的异常
- 资源清理:始终使用
finally
或上下文管理器释放资源 - 异常转换:在适当层级将底层异常转换为高层业务异常
- 日志记录:使用
logging
模块记录异常详细信息 - 避免滥用:不用异常处理常规控制流(性能损耗可达10-100倍)
import logging
logging.basicConfig(level=logging.ERROR)
class PaymentSystem:
def process_payment(self, amount):
"""处理支付请求
可能抛出:
PaymentError - 支付业务错误
ConnectionError - 网络连接错误
"""
try:
if amount <= 0:
raise ValueError("无效金额")
# 模拟支付网关调用
self._call_gateway(amount)
except (TimeoutError, ConnectionResetError) as ce:
logging.error(f"支付系统通信失败: {ce}")
raise ConnectionError("支付服务不可用") from ce
except ValueError as ve:
raise PaymentError("支付参数错误") from ve
except Exception as e:
logging.critical(f"未处理的支付异常: {e}")
raise
def _call_gateway(self, amount):
# 模拟网络故障
raise ConnectionResetError("连接被对端重置")
class PaymentError(Exception):
pass
try:
PaymentSystem().process_payment(-100)
except PaymentError as pe:
print(f"业务错误: {pe}")
except ConnectionError as ce:
print(f"系统错误: {ce}")
5 核心异常类层次
BaseException
├── SystemExit
├── KeyboardInterrupt
├── GeneratorExit
└── Exception
├── StopIteration
├── StopAsyncIteration
├── ArithmeticError
│ ├── FloatingPointError
│ ├── OverflowError
│ └── ZeroDivisionError
├── AssertionError
├── AttributeError
├── BufferError
├── EOFError
├── ImportError
├── LookupError
│ ├── IndexError
│ └── KeyError
├── MemoryError
├── NameError
├── OSError
│ ├── FileNotFoundError
│ ├── PermissionError
│ └── TimeoutError
├── ReferenceError
├── RuntimeError
├── SyntaxError
├── SystemError
├── TypeError
└── ValueError
6 调试技巧
import traceback
def debug_exception():
try:
1/0
except Exception:
# 获取完整堆栈跟踪
tb_str = traceback.format_exc()
print(f"完整堆栈:\n{tb_str}")
# 获取当前异常信息
current_tb = traceback.format_exception_only(*sys.exc_info()[:2])
print(f"当前异常: {''.join(current_tb)}")
# 提取堆栈帧
frames = traceback.extract_tb(sys.exc_info()[2])
for frame in frames:
print(f"文件: {frame.filename}, 行号: {frame.lineno}, 函数: {frame.name}")
debug_exception()
掌握异常处理的精髓在于:理解异常是错误传播机制而非常规控制流工具,合理使用可大幅提升代码健壮性,滥用则会导致性能下降和逻辑混乱。