在Python中,异常处理通过try/except/else/finally结构和raise语句来实现。
try定义了受保护的代码块。如果其中发生异常,控制权将转移到最近的适当except块。如果没有异常发生,则执行else块(如果存在)。finally块始终执行—无论是否有异常(例如,用于释放资源)。
raise语句显式引发异常或重新引发当前异常(在except块中未指定类型)。
示例:
try: x = 1 / 0 except ZeroDivisionError as e: print(f"错误: {e}") else: print("没有错误") finally: print("始终执行")
输出:
错误: division by zero
始终执行
细节:
except的顺序很重要:从特定类型到更通用的(否则特定的将不会被处理)。finally块不能阻止异常的重新抛出(如果在finally中插入raise— 仅最新的"错误"有效)。问题: "如果在try块和finally中引发不同的异常,会发生什么?"
答案: 来自finally的异常会"覆盖"来自try的异常:外部会抛出在finally中引发的异常。
def foo(): try: raise ValueError("在try中") finally: raise IndexError("在finally中") try: foo() except Exception as e: print(repr(e)) # 输出: IndexError('在finally中')
故事
在ETL过程中,在finally中无条件地关闭与数据库的连接,但忘记了在finally中可能会引发异常(例如,如果连接已经关闭)。结果是,来自finally的"隐藏"异常完全吞噬了来自主代码的异常,调试变得异常复杂。
故事
使用多个except链:从一般的except Exception到特定的。结果是,所有特定的except都被"封杀"— 低级别的异常没有单独捕获,导致特定错误的处理变得困难。
故事
在web服务中,在except块中忘记通过"raise"抛出异常,记录错误,但允许继续执行。结果是实际错误被"丢失",程序继续在不正确的状态下运行。