Python 错误处理

Python 的 try/except 异常处理机制、常见异常类型与最佳实践。

#type / concept #status / growing #resource / python #tech / lang / python

[!info] related notes

Python 错误处理

一句话定义

Python 用 try/except 捕获和处理运行时异常,防止程序因意外错误崩溃。

核心机制

基本语法

try:
    # 可能出错的代码
    result = 10 / 0
except ZeroDivisionError:
    # 处理特定异常
    print("不能除以零")

完整结构

try:
    data = json.loads('{"name": "Alice"}')
except json.JSONDecodeError as e:
    # as e 可以拿到错误详情
    print(f"JSON 解析失败: {e}")
except KeyError as e:
    print(f"缺少字段: {e}")
else:
    # 没有异常时执行
    print("解析成功")
finally:
    # 无论如何都会执行(清理资源)
    print("处理完毕")

捕获多种异常

try:
    value = some_dict["key"]
except (KeyError, TypeError) as e:
    # 同时捕获多种异常
    print(f"读取失败: {e}")

不推荐的写法

try:
    do_something()
except:
    # ❌ 裸 except 会捕获所有异常,包括 KeyboardInterrupt
    # 隐藏了真正的错误,调试困难
    pass

常见异常类型

异常触发场景示例
KeyError字典中 key 不存在{}["missing"]
TypeError类型不匹配"hello" + 42
ValueError值不合法int("abc")
AttributeError对象没有该属性"hello".fake_method()
IndexError列表索引越界[1,2,3][10]
FileNotFoundError文件不存在open("nope.txt")
ZeroDivisionError除以零1 / 0
ImportError模块导入失败import nonexistent
json.JSONDecodeErrorJSON 解析失败json.loads("not json")

实战场景

场景 1:安全读取嵌套数据(AI API 响应)

try:
    content = response["choices"][0]["delta"]["content"]
except (KeyError, IndexError):
    content = None

# 或者用 get 链式访问(更简洁)
content = response.get("choices", [{}])[0].get("delta", {}).get("content")

场景 2:网络请求失败重试

import requests

for attempt in range(3):
    try:
        r = requests.get("https://api.example.com", timeout=5)
        r.raise_for_status()  # 4xx/5xx 时抛异常
        break
    except requests.RequestException as e:
        print(f"请求失败 (第{attempt+1}次): {e}")
        if attempt == 2:
            raise

场景 3:自定义异常

class APIError(Exception):
    def __init__(self, status_code, message):
        self.status_code = status_code
        self.message = message

# 使用
try:
    if r.status_code != 200:
        raise APIError(r.status_code, "请求失败")
except APIError as e:
    print(f"API 错误 {e.status_code}: {e.message}")

边界与易混淆点

  1. except Exception vs 裸 exceptexcept Exception 捕获大部分异常但不包括 SystemExitKeyboardInterrupt;裸 except 什么都能捕获,不推荐
  2. as e 不是必须的:如果不需要错误详情,可以省略
  3. finally 的用途:关闭文件、释放锁、断开连接等清理工作
  4. 异常是有成本的:不要用异常做正常流程控制(EAFP 原则虽好,但高频路径上 try/except 比 if 判断慢)
  5. raise 重新抛出:在 except 块中用 raise 可以继续传播异常,常用于日志记录后重新抛出
创建于 2026/6/6 更新于 2026/6/6