前端 Python 3.12

8. 错误和异常

语法错误与异常分流、try/except/else/finally、raise 与异常链、with 协议、ExceptionGroup——对齐 Promise/finally 但要理解修复与再抛。

8.1 语法错误 vs 异常

  • SyntaxError:解析失败(漏冒号、缩进错误等)。
  • Exception:运行期失败(TypeErrorValueErrorKeyError…)。
try:
    {}["missing"]
except KeyError as err:
    print("找不到键:", err)

8.2 try / except / else / finally

  1. 执行 try
  2. 出现异常 → 匹配 except
  3. 无异常else
  4. 几乎总会finally(除非进程被杀、os._exit 等)。
while True:
    try:
        x = int(input("请输入数字: "))
    except ValueError:
        print("不是合法整数,重试")
    else:
        break  # 只有成功解析才跳出
def read_int_header(path: str) -> int:
    f = None
    try:
        f = open(path, encoding="utf-8")
        return int(f.readline())
    except OSError:
        print("打不开文件")
        raise  # 重新抛出:交给上层处理
    except ValueError:
        print("首行不是整数")
        return 0
    finally:
        if f is not None:
            f.close()

文件更常见写 with open(...) as f:;这里故意展示 finally 手动清理的模式。


8.3 raisefrom(异常链)

raise ≈ 前端的 throw:主动抛错,交给 try/except(类似 try/catch)或继续向外冒泡。except 里单独写 raisethrow err,原样再抛。

try:
    open("配置文件.ini", encoding="utf-8")
except OSError as exc:
    raise RuntimeError("无法加载配置") from exc

raise ... from excthrow new Error("无法加载配置", { cause: exc })(把底层错误挂到 cause,栈/日志里能串起来)。raise ... from None故意不传 cause,对外只暴露上层文案(排障信息会变少)。


8.4 自定义异常

class AuthError(Exception):
    """认证失败"""


def login(token: str | None) -> None:
    if not token:
        raise AuthError("缺少 token")

8.5 with 与上下文管理器

with open("test.txt", encoding="utf-8") as f:
    print(f.read())

上下文协议也用于锁、数据库连接等;等价于「无论成功失败都走退出逻辑」。


8.6 ExceptionGroupexcept*

def task() -> None:
    raise ExceptionGroup(
        "批量失败",
        [OSError("磁盘"), ValueError("参数")],
    )


try:
    task()
except* OSError as eg:
    print("OS 问题:", eg.exceptions)
except* ValueError as eg:
    print("参数问题:", eg.exceptions)

8.7 finallyreturn(隐蔽坑)

在 Python 里,若 finally 里执行了 return,会取代 try(以及 except)里的返回值

def confusing() -> int:
    try:
        return 1
    finally:
        return 2  # 会覆盖 try 的 return —— 尽量避免


print(confusing())  # 2

8.8 最佳实践

  1. 精确捕获:能处理再捕获;不要 except Exception: pass 除非真有全局兜底策略。
  2. 资源with 优于手写 close
  3. 日志logging.exception("msg")except 块里会自动附加栈。
  4. 业务语义:自定义异常类型让上层 switch/match 更容易。

权威延伸8. Errors and Exceptions

On this page