异常处理

  • Python 异常处理是一种机制,用于在程序执行过程中处理和管理错误或异常情况。当程序出现错误或异常时,可以使用异常处理来捕获并处理这些异常,以避免程序崩溃或产生不可预料的结果。
  • 在 Python 中,异常是指在程序执行期间发生的错误或异常情况。当异常发生时,程序会抛出一个异常对象,可以通过异常处理来捕获并对其进行处理。
异常名称 描述
BaseException 所有异常的基类
SystemExit 解释器请求退出
KeyboardInterrupt 用户中断执行 (通常是输入 ^C)
Exception 常规错误的基类
StopIteration 迭代器没有更多的值
GeneratorExit 生成器 (generator) 发生异常来通知退出
StandardError 所有的内建标准异常的基类
ArithmeticError 所有数值计算错误的基类
FloatingPointError 浮点计算错误
OverflowError 数值运算超出最大限制
ZeroDivisionError 除 (或取模) 零 (所有数据类型)
AssertionError 断言语句失败
AttributeError 对象没有这个属性
EOFError 没有内建输入,到达 EOF 标记
EnvironmentError 操作系统错误的基类
IOError 输入 / 输出操作失败
OSError 操作系统错误
WindowsError 系统调用失败
ImportError 导入模块 / 对象失败
LookupError 无效数据查询的基类
IndexError 序列中没有此索引 (index)
KeyError 映射中没有这个键
MemoryError 内存溢出错误 (对于 Python 解释器不是致命的)
NameError 未声明 / 初始化对象 (没有属性)
UnboundLocalError 访问未初始化的本地变量
ReferenceError 弱引用 (Weak reference) 试图访问已经垃圾回收了的对象
RuntimeError 一般的运行时错误
NotImplementedError 尚未实现的方法
SyntaxError Python 语法错误
IndentationError 缩进错误
TabError Tab 和空格混用
SystemError 一般的解释器系统错误
TypeError 对类型无效的操作
ValueError 传入无效的参数
UnicodeError Unicode 相关的错误
UnicodeDecodeError Unicode 解码时的错误
UnicodeEncodeError Unicode 编码时错误
UnicodeTranslateError Unicode 转换时错误
Warning 警告的基类
DeprecationWarning 关于被弃用的特征的警告
FutureWarning 关于构造将来语义会有改变的警告
OverflowWarning 旧的关于自动提升为长整型 (long) 的警告
PendingDeprecationWarning 关于特性将会被废弃的警告
RuntimeWarning 可疑的运行时行为 (runtime behavior) 的警告
SyntaxWarning 可疑的语法的警告
UserWarning 用户代码生成的警告

基本语法

try-except 语句

  • try 块用于包含可能会引发异常的代码,except 块用于捕获并处理异常。语法如下:
    1
    2
    3
    4
    try:
    # 可能引发异常的代码
    except ExceptionType:
    # 异常处理代码
  • try 块中的代码执行期间,如果发生了指定类型的异常,那么程序会跳转到对应的 except 块中执行异常处理代码。如果没有发生异常,则 except 块会被跳过。
  • 此外,还可以使用 as 关键字将捕获的异常赋值给一个变量,以便进一步处理或分析异常信息。例如:
    1
    2
    3
    4
    try:
    # 可能引发异常的代码
    except ValueError as e:
    # 处理 ValueError 异常的代码,可以使用 e 变量获取异常对象

捕获多个异常

  • 在 Python 中,可以使用多个 except 语句来捕获多个异常。这样可以根据不同的异常类型执行相应的处理逻辑。具体的语法如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    try:
    # 可能引发异常的代码
    except ExceptionType1:
    # 处理 ExceptionType1 异常的代码
    except ExceptionType2:
    # 处理 ExceptionType2 异常的代码
    ...
    except ExceptionTypeN:
    # 处理 ExceptionTypeN 异常的代码
  • 在上述代码中,try 块中的代码执行期间,如果发生了指定类型的异常,程序会跳转到对应的 except 块中执行异常处理代码。如果没有发生异常或发生的异常类型不在指定的异常类型列表中,则 except 块会被跳过。
  • 可以根据需要捕获多个不同类型的异常,每个 except 块可以处理不同的异常类型。如果多个异常类型具有相同的处理逻辑,可以将它们放在同一个 except 块中,用逗号分隔(分组处理)。下面是一个示例,演示了如何捕获多个异常:
    1
    2
    3
    4
    5
    6
    7
    8
    try:
    # 可能引发异常的代码
    except ValueError:
    # 处理 ValueError 异常的代码
    except ZeroDivisionError:
    # 处理 ZeroDivisionError 异常的代码
    except (TypeError, IndexError):
    # 处理 TypeError 和 IndexError 异常的代码
  • 在上述代码中,try 块中的代码执行期间,如果发生了 ValueError 异常,则程序会跳转到第一个 except 块中处理;如果发生了 ZeroDivisionError 异常,则程序会跳转到第二个 except 块中处理;如果发生了 TypeErrorIndexError 异常,则程序会跳转到第三个 except 块中处理。
  • 需要注意的是,多个 except 块的顺序很重要。Python 会按照从上到下的顺序依次匹配异常类型,只会执行第一个匹配的 except 块。如果多个异常类型之间存在继承关系,应该将子类的异常类型放在父类的异常类型之前,以确保异常类型的匹配顺序正确。

else 语句

else 块可选,用于在 try 块中的代码执行完毕且没有发生异常时执行。语法如下:

1
2
3
4
5
6
try:
# 可能引发异常的代码
except ExceptionType:
# 异常处理代码
else:
# 没有发生异常时执行的代码

如果 try 块中的代码执行完毕且没有发生异常,那么程序会跳转到 else 块中执行。

finally 语句

finally 块可选,用于包含无论是否发生异常都需要执行的代码。无论是否发生异常,finally 块中的代码都会被执行。语法如下:

1
2
3
4
5
6
try:
# 可能引发异常的代码
except ExceptionType:
# 异常处理代码
finally:
# 无论是否发生异常都会执行的代码

finally 块通常用于释放资源或执行清理操作,比如关闭文件或数据库连接。

综合示例

1
2
3
4
5
6
7
8
9
10
try:
# 可能会引发异常的代码块
except ExceptionType1:
# 处理 ExceptionType1 类型的异常
except ExceptionType2:
# 处理 ExceptionType2 类型的异常
else:
# 如果没有发生异常,执行的代码块
finally:
# 无论是否发生异常,都会执行的代码块

raise 语句

  • raise 语句用于在 Python 中显式地触发异常。它允许程序员手动引发异常,并将异常对象传递给异常处理机制。通过使用 raise 语句,可以在特定条件下主动引发异常,以便控制程序的流程和错误处理。raise 语句的基本语法如下:
    1
    raise ExceptionType("error message")
  • 其中,ExceptionType 表示要引发的异常类型,可以是内置的异常类型(如 ValueErrorTypeError 等),也可以是自定义的异常类型。"error message" 是可选的错误消息,用于提供关于异常的额外信息。
  • 下面是一个简单的示例,演示了如何使用 raise 语句引发异常:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    def divide(a, b):
    if b == 0:
    raise ValueError("除数不能为零")
    return a / b


    try:
    result = divide(10, 0)
    except ValueError as e:
    print("捕获到异常:", e)

  • 在上述代码中,divide 函数用于执行除法运算。在函数内部,我们使用条件判断来检查除数是否为零,如果为零,则使用 raise 语句引发 ValueError 异常,并提供错误消息。
  • try 块中调用 divide 函数时,由于除数为零,会触发 ValueError 异常。然后,异常被捕获并赋值给 e 变量,在 except 块中打印异常信息。
  • 使用 raise 语句可以灵活地控制程序的异常处理流程。通过根据特定条件引发异常,我们可以在需要的地方中断程序的执行,并通过异常处理机制来处理异常情况。这可以帮助我们更好地管理错误和异常,并提供有用的错误信息。

嵌套异常

  • 嵌套异常是指在处理异常时,一个异常的处理过程中又引发了另一个异常。当发生嵌套异常时,内部异常会覆盖外部异常,而外部异常则成为内部异常的上下文。
  • 在 Python 中,可以通过在 except 块内部使用 raise 语句来引发新的异常,从而实现嵌套异常。这可以在处理异常时,根据需要引发新的异常,以提供更具体的错误信息或执行额外的错误处理逻辑。
  • 下面是一个简单的示例,演示了嵌套异常的概念:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    try:
    try:
    # 可能引发异常的代码
    except ExceptionType1:
    # 处理 ExceptionType1 异常的代码
    raise ExceptionType2("内部异常")
    except ExceptionType2 as e:
    # 处理 ExceptionType2 异常的代码,可以访问内部异常的上下文信息
    print("捕获到内部异常:", e)
  • 在上述代码中,我们使用了嵌套的 try-except 块。内部的 try 块用于执行可能引发异常的代码,如果发生了 ExceptionType1 异常,会跳转到内部的 except 块中处理。在内部的 except 块中,我们使用 raise 语句引发了一个新的 ExceptionType2 异常,并提供了错误消息。
  • 外部的 try-except 块用于处理内部引发的异常。如果发生了 ExceptionType2 异常,会跳转到外部的 except 块中处理,并打印异常信息。
  • 嵌套异常允许我们在异常处理过程中引发新的异常,从而提供更多的上下文信息或执行额外的错误处理逻辑。但需要注意,在处理嵌套异常时,要确保适当地处理内部和外部异常,以避免异常被忽略或引发未处理的异常。

自定义异常

  • 在 Python 中,我们可以通过创建自定义异常类来定义自己的异常。自定义异常可以用于在特定条件下引发异常,并提供更具体的错误信息或执行特定的错误处理逻辑。
  • 自定义异常类可以继承自内置的异常类(如 ExceptionValueError 等),也可以继承自其他自定义异常类。通常,我们会选择继承自适当的内置异常类,以便在异常处理过程中能够正确地捕获和处理自定义异常。
  • 下面是一个示例,演示了如何创建自定义异常类:
    1
    2
    3
    class MyCustomException(Exception):
    pass

  • 在上述代码中,我们创建了一个名为 MyCustomException 的自定义异常类,它继承自内置的 Exception 类。pass 语句表示该类不包含任何额外的定义,因此它只是一个简单的自定义异常类。
  • 可以根据需要在自定义异常类中添加属性和方法,以提供更多的上下文信息或自定义的行为。例如:
    1
    2
    3
    4
    5
    6
    7
    8
    class MyCustomException(Exception):
    def __init__(self, message, error_code):
    super().__init__(message)
    self.error_code = error_code

    def print_error(self):
    print(f"错误代码: {self.error_code},错误信息: {self.args[0]}")

  • 在上述代码中,我们添加了一个 __init__ 方法来接收错误消息和错误代码,并使用 super() 调用父类的 __init__ 方法来设置错误消息。我们还添加了一个 print_error 方法,用于打印错误代码和错误信息。
  • 使用自定义异常时,可以通过使用 raise 语句引发自定义异常来触发异常情况。例如:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    def process_data(data):
    if not data:
    raise MyCustomException("数据为空", 1001)


    try:
    process_data([])
    except MyCustomException as e:
    e.print_error()

  • 在上述代码中,process_data 函数用于处理数据。如果数据为空,我们使用 raise 语句引发了 MyCustomException 异常,并提供了错误消息和错误代码。在 except 块中捕获到该异常后,我们可以通过调用 print_error 方法打印错误信息。
  • 通过创建自定义异常类,我们可以更好地组织和管理异常,并提供更具体的错误信息和自定义的异常处理逻辑。这有助于使代码更具可读性和可维护性,并提供更好的错误诊断和调试能力。

断言

  • 简介
    断言(Assertion)是一种在程序中检查条件是否满足的方法。在 Python 中,断言是通过 assert 语句实现的。它用于在代码中插入检查点,以确保程序的正确性。
  • 语法
    1
    assert condition, message

    其中,condition 是一个布尔表达式,表示要检查的条件。如果条件为真(True),则程序继续执行;如果条件为假(False),则触发 AssertionError 异常,并可选地输出指定的错误消息(message)。

  • 工作原理
    1. 执行 assert 语句时,首先计算条件表达式的值。
    2. 如果条件为真,则程序继续执行。
    3. 如果条件为假,则触发 AssertionError 异常。
    4. 可选地输出指定的错误消息。
  • 作用
    1. 调试和测试:断言可用于验证程序的正确性和健壮性。通过在关键位置插入断言语句,可以确保程序的状态和结果符合预期。如果断言失败,就意味着程序存在问题,可以帮助我们快速定位和修复错误。
    2. 前置条件和后置条件:断言可用于检查函数或方法的输入参数和返回值是否满足预期。通过在函数或方法的开头和结尾处添加断言语句,可以确保输入和输出符合约定和要求。
    3. 程序逻辑的约束:断言可用于强制执行程序中的逻辑约束。例如,如果在一段代码中假设某个变量的值不会为零,可以使用断言来验证这个假设,并在条件不满足时触发异常。
  • 注意事项
    需要注意的是,断言通常用于调试和开发阶段,而不是用于处理预期的运行时错误。在生产环境中,可以通过关闭断言来避免性能损失。可以使用 -O 选项或设置 PYTHONOPTIMIZE 环境变量为 2 来禁用断言。
  • 示例
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    def divide(a, b):
    assert b != 0, "除数不能为零"
    return a / b


    result = divide(10, 2)
    print(result) # 输出: 5.0

    result = divide(10, 0) # 触发AssertionError异常,并输出错误消息

    在上述代码中,divide 函数用于执行除法运算。在函数内部,我们使用断言来检查除数是否为零,如果为零,则触发 AssertionError 异常,并输出错误消息。