Python错误与异常处理

  • Post category:Python

Python错误与异常处理

在使用 Python 编写程序时,有时候我们会遇到各种各样的错误和异常。这些错误和异常可能是因为代码出现了语法错误,也可能是由于不恰当的输入数据或计算逻辑导致的。本文将对 Python 错误和异常处理进行详细介绍,包括:

  1. 错误和异常的分类
  2. try-except 语句
  3. finally 语句
  4. raise 语句
  5. assert 语句

错误和异常的分类

在 Python 中,错误和异常是不同的概念。错误通常是指程序因为语法或者逻辑上的错误而不能正常编译和执行,可以分为以下几类:

  • 语法错误:也称为解析错误,在编写程序时,如果 Python 解释器无法解析代码,就会发生语法错误。
  • 运行时错误:也称为异常,是指程序在运行过程中遇到的错误。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 转换时错误

try-except 语句

通过 try-except 语句可以对 Python 抛出的异常进行捕获和处理。try-except 语句的一般形式如下:

try:
    # 可能会出现异常的代码
except 错误类型1:
    # 如果遇到错误类型1,执行该段代码
except 错误类型2:
    # 如果遇到错误类型2,执行该段代码
...
except Exception as e:
    # 对于所有未捕获的异常,执行该段代码。将异常信息保存在变量 e 中
else:
    # 没有出现异常,执行该段代码
finally:
    # 无论是否出现异常,都会执行该段代码

在这里,需要注意以下几点:

  • 可以有多个 except 语句,用于捕获不同类型的异常,但是只有一个 except 语句会被执行。如果异常类型匹配多个 except 语句,只有第一个符合条件的 except 语句会被执行。
  • 如果没有发生异常,else 语句块内的代码会被执行。
  • 不管是否发生异常,finally 语句块内的代码都会被执行。它通常被用于清理资源,比如关闭打开的文件。在最后一个 except 块内 raise 语句抛出异常,则 finally 块仍然会执行。

下面是一个简单的示例,该示例从文件中读取数字,如果文件不存在或文件中包含非数字字符,就会抛出异常。利用 try-except 语句来处理这些异常,保证程序不会崩溃,并输出错误信息:

try:
    with open("numbers.txt") as f:
        lines = f.readlines()
        result = 0
        for line in lines:
            try:
                result += int(line.strip())
            except ValueError:
                print(f"error: {line.strip()} is not a number")
except FileNotFoundError:
    print("error: file not found")
finally:
    f.close()

finally 语句

finally 语句块内的代码无论是否出现异常,都会被执行。finally 语句通常用于保证一些资源被释放,比如关闭打开的文件或者清理临时文件。下面是一个简单的示例,展示了如何使用 try-finally 语句来关闭文件并释放占用的内存资源:

f = None
try:
    f = open("file.txt", "r")
    lines = f.readlines()
    # 读取文件内容,进行其他操作
except IOError as e:
    print("Error: cannot read file.", e.errno, e.strerror)
finally:
    if f:
        f.close()

raise 语句

Python 中的 raise 语句用于手动抛出异常。 raise 语句的一般形式如下:

raise Exception("错误信息")

在这里, Exception 是一个错误类型,可以根据需要替换为其他错误类型。下面是一个简单的示例,该示例演示了如何手动抛出异常:

def divide_two_numbers(a, b):
    if b == 0:
        raise ValueError("Division by zero")
    return a / b

try:
    result = divide_two_numbers(10, 0)
except ValueError as e:
    print(e)

在这个示例中, divide_two_numbers 函数用于计算两个数的商。如果第二个数为零,函数会手动抛出一个 ValueError 异常,这时候我们可以利用 try-except 语句来捕捉并处理这个异常。

assert 语句

assert 语句用于断言一个条件是否为真。如果条件为假,则会抛出 AssertionError 异常,该异常可以捕获并处理。assert 语句的一般形式如下:

assert condition, message

在这里, condition 是需要判断的条件,如果为假,则抛出异常;message 是一个字符串,用于说明断言失败的原因。下面是一个简单的示例,该示例演示了如何使用 assert 语句来进行输入检查:

def sqrt(x):
    assert x >= 0, "x must be non-negative"
    # 计算并返回 x 的平方根
    return x ** 0.5

try:
    result = sqrt(-1)
except AssertionError as e:
    print(e)

在这个示例中, sqrt 函数用于计算一个数的平方根。函数使用 assert 语句来检查输入是否大于等于零,如果条件不满足,则抛出 AssertionError 异常。