当前位置:首页>python>【一起学 Python】第 58 天:捕获特定异常与异常对象信息

【一起学 Python】第 58 天:捕获特定异常与异常对象信息

  • 2026-09-03 08:43:53
【一起学 Python】第 58 天:捕获特定异常与异常对象信息

欢迎来到 Python 学习计划的第 58 天!🎉

昨天我们学习了 try-except 基本语法,知道了如何防止程序崩溃。但仅仅捕获异常是不够的,我们需要知道发生了什么错误以及在哪里发生的。

今天我们将深入 异常对象内部,学习如何捕获特定异常、获取错误详情以及查看堆栈信息。这是编写健壮程序的关键一步!

一、捕获特定异常

Python 有丰富的内置异常类型,应该根据实际情况捕获特定的异常,而不是笼统地捕获所有错误。

1. 为什么要捕获特定异常?

  • 精确处理:不同类型的错误需要不同的处理逻辑。
  • 避免掩盖错误:防止意外捕获了未预期的错误(如 KeyboardInterrupt)。

2. 常见异常类型

# ValueError: 值错误try:    value = int("abc")except ValueError:    print("值转换错误")# ZeroDivisionError: 除零错误try:    result = 10 / 0except ZeroDivisionError:    print("除以零错误")# KeyError: 字典键不存在try:    data = {"name": "张三"}    print(data["age"])except KeyError:    print("键不存在")

3. 捕获多种异常

可以使用元组一次性捕获,或使用多个 except 块。

# 方式 1:多个 except 块(推荐,便于区分处理)try:    num = int(input("输入:"))    result = 100 / numexcept ValueError:    print("输入不是整数")except ZeroDivisionError:    print("除数为零")# 方式 2:元组捕获(处理逻辑相同时)try:    num = int(input("输入:"))    result = 100 / numexcept (ValueError, ZeroDivisionError) as e:    print(f"输入错误:{e}")

二、异常对象信息

使用 as 关键字可以将异常实例赋值给变量,从而访问错误的详细信息。

1. 基本属性

try:    raise ValueError("这是错误信息")except ValueError as e:    print(f"异常类型:{type(e).__name__}")  # ValueError    print(f"异常信息:{e}")                  # 这是错误信息    print(f"异常参数:{e.args}")             # ('这是错误信息',)

2. 特定异常的特有属性

不同异常类型可能包含额外的信息(如文件名、错误号等)。

# FileNotFoundErrortry:    with open("不存在的文件.txt") as f:        passexcept FileNotFoundError as e:    print(f"文件名:{e.filename}")    # 不存在的文件.txt    print(f"错误号:{e.errno}")       # 2    print(f"错误信息:{e.strerror}")  # No such file or directory# KeyErrortry:    data = {"name": "张三"}    value = data["age"]except KeyError as e:    print(f"缺失的键:{e.args[0]}")  # age

三、获取完整的堆栈信息

当需要记录详细错误日志时,可以使用 traceback 模块获取完整的错误堆栈。

1. 使用 traceback 模块

import tracebackdef inner_function():    raise ValueError("内部错误")def outer_function():    inner_function()try:    outer_function()except ValueError as e:    # 获取格式化的堆栈字符串    tb_str = traceback.format_exc()    print("完整堆栈信息:")    print(tb_str)
输出示例:
完整堆栈信息:Traceback (most recent call last):  File "...", line 10, in <module>    outer_function()  File "...", line 7, in outer_function    inner_function()  File "...", line 4, in inner_function    raise ValueError("内部错误")ValueError: 内部错误

2. 使用 sys.exc_info()

获取当前异常的详细信息(类型、值、堆栈跟踪)。

import systry:    1 / 0except ZeroDivisionError:    exc_type, exc_value, exc_tb = sys.exc_info()    print(f"异常类型:{exc_type}")    print(f"异常值:{exc_value}")    print(f"堆栈跟踪:{exc_tb}")

四、异常层次结构

Python 的异常形成层次结构,可以通过捕获父类异常来处理多种子类异常。

BaseException├── SystemExit├── KeyboardInterrupt└── Exception    ├── ArithmeticError(算术错误)    │   └── ZeroDivisionError    ├── LookupError (查找错误)    │   ├── IndexError    │   └── KeyError    ├── OSError (系统错误)    │   └── FileNotFoundError    ├── ValueError    └── TypeError

捕获父类异常

try:    # 可能抛出 IndexError 或 KeyError    passexcept LookupError as e:  # 捕获两者的父类    print(f"查找错误:{e}")

五、实战应用示例

1. 详细错误日志

在生产环境中,记录完整的错误信息便于排查问题。

import tracebackimport logginglogging.basicConfig(level=logging.ERROR)def divide(a, b):    try:        return a / b    except ZeroDivisionError as e:        logging.error(f"除法错误:{e}")        logging.error(f"参数:a={a}, b={b}")        logging.error(f"堆栈:\n{traceback.format_exc()}")        return Noneresult = divide(10, 0)

2. 文件操作的详细错误信息

根据具体异常类型返回不同的错误提示。

def read_file_safe(filepath):    try:        with open(filepath, "r", encoding="utf-8") as f:            return {"success": True, "content": f.read()}    except FileNotFoundError as e:        return {            "success": False,            "error": "文件不存在",            "filename": e.filename        }    except PermissionError as e:        return {            "success": False,            "error": "权限不足",            "filename": e.filename        }    except UnicodeDecodeError as e:        return {            "success": False,            "error": "编码错误",            "encoding": e.encoding        }result = read_file_safe("不存在.txt")print(result)

3. 自定义异常处理器

统一处理不同类型的异常,返回友好的错误消息。

def handle_exception(e):    """统一的异常处理函数"""    error_type = type(e).__name__    handlers = {        "ValueError": lambda e: f"值错误:{e}",        "TypeError": lambda e: f"类型错误:{e}",        "KeyError": lambda e: f"键 '{e.args[0]}' 不存在",        "FileNotFoundError": lambda e: f"文件 '{e.filename}' 不存在",    }    handler = handlers.get(error_type, lambda e: f"未知错误:{e}")    return handler(e)# 测试errors = [ValueError("无效值"), KeyError("username")]for e in errors:    print(handle_exception(e))

六、注意事项与最佳实践

建议

说明

具体优先

先捕获具体异常,再捕获通用异常(Exception)

记录堆栈

生产环境应记录完整的堆栈信息(traceback)

不要忽略

获取异常信息后要适当处理,不要直接 pass

敏感信息

注意不要将详细错误信息直接暴露给最终用户

层次结构

利用异常继承关系,用父类捕获多种子类异常

常见误区

  1. 捕获所有异常:except: 会捕获包括 KeyboardInterrupt 在内的所有错误,导致程序无法正常退出。
  2. 不记录日志:只打印简单错误信息,丢失了堆栈上下文,难以调试。
  3. 暴露敏感信息:将数据库错误或文件路径直接显示给用户,可能存在安全风险。

七、总结

知识点

说明

特定异常

捕获 ValueError, ZeroDivisionError 等具体类型

异常对象

使用 as e 获取,访问 args, filename 等属性

堆栈信息

使用 traceback.format_exc() 获取完整错误链

层次结构

可以通过捕获父类(如 LookupError)处理多种子类

最佳实践

具体优先,记录日志,不暴露敏感信息

掌握异常对象的详细信息,能让你的错误处理逻辑更加精准,调试问题更加高效。

📌 明日预告:else 与 finally 的执行时机

明天我们将进入 异常与文件模块第三天!

  • 主题:else 与 finally 的执行时机
  • 核心问题:
    1. try-except-else-finally 的完整结构是什么?
    2. else 块什么时候执行?(没有异常时)
    3. finally 块什么时候执行?(无论是否异常)
    4. 资源清理的最佳实践是什么?
    5. 执行顺序是怎样的?

💡 提前思考:

  1. 如果 try 块中没有异常,except 不执行,那 else 会执行吗?
  2. 如果 try 块中有 return,finally 还会执行吗?
  3. 为什么推荐用 finally 来关闭文件?

掌握特定异常捕获,让错误处理更精准!继续加油!🚀

最新文章

随机文章