杰瑞科技汇

Python exception 信息如何高效捕获与处理?

理解 Python 的异常信息是调试代码的关键,当你写的代码出现错误时,Python 会“抛出”(raise)一个异常,如果没有被捕获,程序就会中断并打印出详细的错误信息,学会阅读这些信息,你就能快速定位问题所在。

Python exception 信息如何高效捕获与处理?-图1
(图片来源网络,侵删)

一个典型的异常信息结构

我们来看一个最常见的例子:ZeroDivisionError

# 一个会引发异常的代码
def divide(a, b):
    return a / b
# 调用函数,传入除数为0
result = divide(10, 0)
print("计算结果:", result)

运行这段代码,你会看到类似下面的输出:

Traceback (most recent call last):
  File "example.py", line 8, in <module>
    result = divide(10, 0)
  File "example.py", line 5, in divide
    return a / b
ZeroDivisionError: division by zero

这个异常报告分为几个关键部分,我们逐一解析:

Traceback (most recent call last) - 追踪信息

这是异常报告的标题,告诉你这是一个“回溯”或“追踪”信息,它记录了异常发生时,程序执行过的所有函数调用路径,从你运行的脚本开始,一直到发生错误的那一行代码。

Python exception 信息如何高效捕获与处理?-图2
(图片来源网络,侵删)

文件名和行号 (File "example.py", line 8, in <module>)

这是追踪信息中的每一帧,告诉你错误发生的具体位置。

  • File "example.py": 发生错误的文件名。
  • line 8: 发生错误的行号。
  • in <module>: 发生错误时,程序正在执行的代码所在的函数或作用域<module> 表示这是在主程序模块(也就是你直接运行的脚本)中,而不是在某个函数内部。

如果错误发生在函数内部,你会看到更深的调用栈:

  File "example.py", line 8, in <module>
    result = divide(10, 0)
  File "example.py", line 5, in divide  <-- 错误发生的函数
    return a / b

这清晰地告诉我们:<module> 中的第 8 行调用了 divide 函数,然后在 divide 函数的第 5 行发生了错误。

异常类型 (ZeroDivisionError)

这是错误的核心类型,Python 中有很多内置的异常类型,每种类型代表一种特定类型的错误。

Python exception 信息如何高效捕获与处理?-图3
(图片来源网络,侵删)
  • NameError: 尝试访问一个未定义的变量。
  • TypeError: 对类型不兼容的值进行操作(将字符串和数字相加)。
  • ValueError: 传入的值类型正确,但内容不合适(int('abc'))。
  • IndexError: 访问序列中不存在的索引。
  • KeyError: 访问字典中不存在的键。
  • FileNotFoundError: 尝试打开一个不存在的文件。

了解这些异常类型,可以帮助你快速判断问题的性质。

异常消息 (division by zero)

这是对异常的简短描述,解释了为什么会发生这个错误。ZeroDivisionError 的消息就是 "division by zero",非常直观。


如何处理异常:try...except 语句

当预见到某段代码可能会出错时,你可以使用 try...except 来“捕获”异常,防止程序崩溃,并让程序以更优雅的方式处理错误。

def safe_divide(a, b):
    try:
        # 尝试执行可能出错的代码
        result = a / b
    except ZeroDivisionError:
        # 如果捕获到 ZeroDivisionError,就执行这里的代码
        print("错误:不能除以零!")
        return None  # 返回一个特殊的值表示失败
    else:
        # try 块中的代码没有出错,就执行这里的代码
        return result
    finally:
        # 无论是否发生异常,finally 块中的代码都会被执行
        print("除法运算结束。")
# 测试
print(safe_divide(10, 2))  # 正常情况
print(safe_divide(10, 0))  # 出现异常的情况

输出:

除法运算结束。
5.0
错误:不能除以零!
除法运算结束。
None

try...except 的结构解析:

  • try: 将可能引发异常的代码块放在 try 语句下。
  • except: 指定要捕获的异常类型,你可以捕获一个特定的异常(如 except ZeroDivisionError),也可以捕获所有异常(不推荐,使用 except Exceptionexcept:)。
  • else: 与 try 语句搭配使用,表示如果 try 块没有引发异常,则执行 else 块中的代码。
  • finally: 无论 try 块是否引发异常,finally 块中的代码总会被执行,通常用于清理资源,如关闭文件、释放网络连接等。

如何主动引发异常:raise 语句

除了 Python 自动抛出的异常,你还可以使用 raise 语句在特定条件下主动抛出异常。

def set_age(age):
    if not isinstance(age, int):
        # 如果传入的参数不是整数,就主动抛出一个 TypeError
        raise TypeError("年龄必须是整数")
    if age < 0 or age > 120:
        # 如果年龄不在合理范围内,就主动抛出一个 ValueError
        raise ValueError("年龄必须在 0 到 120 之间")
    print(f"设置的年龄是: {age}")
# 正常调用
set_age(25)
# 会引发 TypeError 的调用
try:
    set_age("twenty-five")
except TypeError as e:
    print(f"捕获到错误: {e}")
# 会引发 ValueError 的调用
try:
    set_age(150)
except ValueError as e:
    print(f"捕获到错误: {e}")

输出:

设置的年龄是: 25
捕获到错误: 年龄必须是整数
捕获到错误: 年龄必须在 0 到 120 之间

使用 raise 可以让你的函数更健壮,并在出现不符合预期的情况时,强制调用者去处理问题。


获取异常的详细信息

except 块中,你可以将异常对象赋给一个变量,从而获取更多关于异常的信息。

try:
    # 尝试打开一个不存在的文件
    with open("non_existent_file.txt", "r") as f:
        content = f.read()
except FileNotFoundError as e:
    # e 就是捕获到的异常对象
    print(f"捕获到异常: {type(e).__name__}")  # 打印异常类型
    print(f"异常消息: {e}")                 # 打印异常消息
    print(f"文件名: {e.filename}")          # 访问异常对象的特定属性

输出:

捕获到异常: FileNotFoundError
异常消息: non_existent_file.txt
文件名: non_existent_file.txt

很多内置的异常对象都包含有用的属性,e.filename(文件名)、e.args(异常参数元组)等。


自定义异常

你可以通过继承 Python 内置的 Exception 类来创建自己的异常类型,从而使你的代码错误处理逻辑更清晰、更具体。

class InvalidPasswordError(Exception):
    """自定义异常,用于密码不符合要求的情况。"""
    def __init__(self, password, message="密码太短,至少需要8个字符"):
        self.password = password
        self.message = message
        super().__init__(self.message)
def check_password(password):
    if len(password) < 8:
        # 抛出自定义的异常
        raise InvalidPasswordError(password)
    print("密码强度符合要求。")
try:
    check_password("123")
except InvalidPasswordError as e:
    print(f"密码设置失败: {e.message} (你输入的密码是: {e.password})")

输出:

密码设置失败: 密码太短,至少需要8个字符 (你输入的密码是: 123)
概念 关键字/语法 作用
异常报告 Traceback Python 解释器打印的错误信息,用于定位问题。
异常捕获 try...except...else...finally 防止程序因错误而崩溃,并优雅地处理错误。
主动抛出 raise 在代码逻辑中主动触发一个异常,强制调用者处理。
异常信息 as e except 块中获取异常对象,以便访问其类型、消息等。
自定义异常 class MyError(Exception): 创建特定业务逻辑的异常,使错误处理更清晰。

掌握 Python 的异常处理机制,是编写健壮、可靠代码的必备技能,下次看到 Traceback 时,不要害怕,把它看作是 Python 在帮你“导航”,告诉你哪里出了问题。

分享:
扫描分享到社交APP
上一篇
下一篇