为什么需要异常

age = int(input("年龄: "))    # 用户输入 "abc" → ValueError,程序崩

异常处理的目的:预测可能出错的地方,给出合理的应对

基本结构

try:
    age = int(input("年龄: "))
    print(f"明年 {age + 1} 岁")
except ValueError:
    print("请输入数字")

多个 except

try:
    n = int(input("分母: "))
    print(10 / n)
except ValueError:
    print("不是数字")
except ZeroDivisionError:
    print("不能除以 0")
except Exception as e:        # 兜底
    print(f"其他错误: {e}")

顺序:具体的异常在前,宽泛的(Exception)在最后。

一个 except 抓多种

try:
    ...
except (ValueError, TypeError) as e:
    print(f"类型相关错误: {e}")

else:没出错才执行

try:
    n = int(input("数字: "))
except ValueError:
    print("失败")
else:
    print(f"成功,值是 {n}")    # 仅在没异常时走

finally:不管出不出错都执行

try:
    f = open("data.txt")
    ...
except FileNotFoundError:
    print("找不到文件")
finally:
    print("清理工作")    # 永远执行

文件清理用 with 更优雅——不需要写 finally。

主动抛异常

def divide(a, b):
    if b == 0:
        raise ValueError("分母不能为 0")
    return a / b

raise 主动抛异常——比返回 None 更明确。

自定义异常

class NotFoundError(Exception):
    pass

def find_user(uid):
    if uid not in db:
        raise NotFoundError(f"用户 {uid} 不存在")
    return db[uid]

反模式:吞掉所有异常

# 别这样写
try:
    do_something()
except:
    pass    # 出了任何错都假装没事——bug 永远找不到

至少打印日志,至少记下异常类型。

实战:安全转换数字

def to_int(s, default=0):
    try:
        return int(s)
    except (ValueError, TypeError):
        return default

to_int("42")      # 42
to_int("abc")     # 0
to_int(None)     # 0

下一篇讲模块与 import——把代码拆到多个文件。