人人都会AI编程

11.2 try/except/else/finally 异常捕获与处理

更新时间:2026-07-12

Python 的异常处理通过 try 复合语句实现,完整语法包含四个子句:tryexceptelsefinally。它们的组合能让你既优雅地应对错误,又保证资源正确释放。

基本结构

try:
    # 可能抛出异常的代码
except SomeException as e:
    # 捕获到特定异常时的处理
else:
    # 没有异常发生时执行
finally:
    # 无论是否异常都会执行(通常用于清理资源)

各子句详解

1. try 子句

  • 执行的代码块,一旦某条语句抛出异常,后续语句就不再执行,直接跳转到匹配的 except 去处理。
try:
    result = 10 / 0          # 抛出 ZeroDivisionError
    print("这行不会执行")
except ZeroDivisionError:
    print("除数不能为零")

2. except 子句

  • 可以捕获一个或多个异常类型,也可以不指定类型(捕获全部)。
  • 支持 as 绑定异常实例,以获取错误详情。
try:
    num = int(input("输入数字: "))
    result = 100 / num
except ValueError:
    print("输入的不是有效数字")
except ZeroDivisionError:
    print("不能输入0")
except (TypeError, KeyError) as e:
    print(f"类型或键错误: {e}")
except Exception as e:          # 兜底,捕获其他未预料异常
    print(f"发生未知错误: {e}")
  • 要点except 按顺序匹配,一旦匹配成功,后面的 except 就不会再检查。所以应当把更具体的异常放在前面,更泛化的(如 Exception)放在最后。

3. else 子句

  • 只有 try没有抛出任何异常时才会执行。
  • 典型用途:把只应在无异常时执行的代码从 try 中移出来,让 try 块只包含可能出错的语句,意图更清晰。
try:
    f = open("data.txt", "r")
except FileNotFoundError:
    print("文件不存在")
else:
    content = f.read()       # 只有文件打开成功,才读取
    print(content)
    f.close()
  • 对比:如果不使用 else,你可能把 content = f.read() 也放在 try 中,但一旦读取时出问题(磁盘坏道等),就会被误认为是文件不存在,异常处理变混乱。elsetry 的职责更单一。

4. finally 子句

  • 无论是否发生异常,也不管异常是否被捕获,finally 中的代码一定会执行(即使 try/except 中有 returnbreak,也会先执行 finally)。
  • 适用于资源释放:关闭文件、释放锁、关闭数据库连接等。
f = None
try:
    f = open("data.txt", "r")
    data = f.read()
except FileNotFoundError:
    print("文件不存在")
finally:
    if f:
        f.close()           # 确保文件一定被关闭
    print("清理完成")

更简洁的方式是使用 with 语句(上下文管理器),它自动帮你处理 finally 的清理逻辑。这也是处理文件等资源的推荐做法

# 推荐:自动关闭文件
try:
    with open("data.txt", "r") as f:
        data = f.read()
except FileNotFoundError:
    print("文件不存在")

组合使用原则

  • try 必须和至少一个 exceptfinally 同时出现。
  • else 必须跟在所有 except 之后,finally 之前。
  • 常用顺序:tryexcept(s) → elsefinally

捕获异常的最佳实践

  • 精确捕获:尽量捕获具体异常类型,避免裸 except:,它会吞掉系统退出异常(SystemExitKeyboardInterrupt)等,导致程序无法正常终止。
  • 记录而不是忽略:如果必须捕获异常且不做处理,至少记录日志,否则问题极难排查。
  • 不建议用异常控制正常流程:异常处理有性能开销,应只用于真正的“异常情况”,而不是代替条件判断。
  • 不要无脑捕获所有异常:有时应当让异常向上传播,由更上层的调用者处理。
# 不好:吞掉一切异常
try:
    do_something()
except:
    pass

实际场景示例

场景1:读取配置文件,不存在则用默认值

try:
    with open("config.json", "r") as f:
        config = json.load(f)
except FileNotFoundError:
    config = {"host": "localhost", "port": 80}
except json.JSONDecodeError:
    print("配置文件格式错误,使用默认配置")
    config = {"host": "localhost", "port": 80}

场景2:处理 API 调用中的网络错误和响应错误

try:
    response = requests.get("https://api.example.com/data", timeout=5)
    response.raise_for_status()          # 4xx/5xx 抛异常
except requests.Timeout:
    print("请求超时")
except requests.ConnectionError:
    print("网络连接问题")
except requests.HTTPError as e:
    print(f"HTTP 错误: {e.response.status_code}")
else:
    data = response.json()               # 只有成功才解析数据
    print(f"获取到 {len(data)} 条记录")
finally:
    print("请求结束")

掌握 try/except/else/finally 的组合运用,能让你的程序在应对不可预测的错误时既健壮又清晰,是写出生产级 Python 代码的基本功。