Python 异常处理 “避坑指南”:别再只会用 print 调试了

50 阅读3分钟

还在靠 print 排查代码报错?遇到 KeyErrorTypeError 就手忙脚乱?这篇进阶偏基础的异常处理技巧,让你的代码从 “一错就崩” 变成 “优雅容错”,新手也能秒上手!

1. try-except 精准捕获:别再一把梭抓所有异常

新手写异常处理总爱用 except Exception 捕获所有错误,看似省事,实则隐藏了真正的 bug!正确姿势是精准捕获特定异常

# 反面教材:捕获所有异常,无法定位问题
nums = [1, 2, 3]
try:
    print(nums[5])  # 索引越界
    print("计算结果:", 10 / 0)  # 除零错误
except Exception as e:
    print("出错了:", e)  # 只知道出错,分不清是索引还是除零问题

# 正确姿势:精准捕获多个特定异常
try:
    print(nums[5])
    print("计算结果:", 10 / 0)
except IndexError as e:
    print(f"索引越界啦: {e}")  # 专门处理索引问题
except ZeroDivisionError as e:
    print(f"不能除以零哦: {e}")  # 专门处理除零问题

2. else-finally 组合拳:异常处理的 “黄金搭档”

你以为 try-except 就够了?elsefinally 能让逻辑更清晰:

  • else无异常时执行,放正常逻辑代码
  • finally无论是否异常都执行,适合释放资源(比如关闭文件)
# 需求:读取文件内容,无异常则打印,最后必关闭文件
file_path = "test.txt"
f = None
try:
    f = open(file_path, "r", encoding="utf-8")
except FileNotFoundError as e:
    print(f"文件找不到: {e}")
else:
    # 没有异常才会执行这里
    content = f.read()
    print("文件内容:", content)
finally:
    # 不管有没有异常,都要关闭文件
    if f:
        f.close()
        print("文件已关闭")

# 进阶:用 with 语句自动关闭资源(替代 finally 手动关文件)
try:
    with open(file_path, "r", encoding="utf-8") as f:
        print(f.read())
except FileNotFoundError:
    print("文件不存在")
# with 会自动调用 close(),不用手动写

3. 主动抛异常:raise 帮你 “自定义报错”

有时候代码没语法错误,但业务逻辑出错了(比如用户输入年龄为负数),这时候就需要用 raise 主动抛出异常,提醒调用者。

# 需求:校验用户年龄,必须大于0
def check_age(age):
    if not isinstance(age, int):
        # 主动抛类型错误
        raise TypeError("年龄必须是整数")
    if age < 0:
        # 主动抛值错误
        raise ValueError("年龄不能是负数")
    print(f"年龄{age}校验通过")

# 测试主动抛异常
try:
    check_age(-10)  # 抛 ValueError
    # check_age("18")  # 抛 TypeError
except (TypeError, ValueError) as e:
    print(f"校验失败: {e}")

4. 异常链:raise ... from 追踪根因

当你在 except 块里又抛出新异常时,用 raise ... from 可以保留原始异常信息,方便排查问题。

# 需求:读取配置文件,解析失败时抛自定义异常
def read_config(file_path):
    try:
        with open(file_path, "r") as f:
            content = f.read()
        # 模拟解析失败
        if not content:
            raise ValueError("配置文件内容为空")
    except FileNotFoundError as e:
        # 抛出新异常,并保留原始异常
        raise RuntimeError("读取配置失败") from e

# 测试异常链
try:
    read_config("config.txt")
except RuntimeError as e:
    print(f"错误: {e}")
    # 打印原始异常(根因)
    print("根因:", e.__cause__)

小总结

  1. 异常捕获要精准,别用 except Exception 一把梭;
  2. else 放正常逻辑,finally 放资源清理,with 语句更优雅;
  3. 业务逻辑错误用 raise 主动抛异常;
  4. 异常链 raise ... from 帮你追踪根因。