Python 中的异常处理

2024 年 8 月 29 日 | 阅读 6 分钟

在深入探讨主题之前,我们需要了解 Python 中的错误和异常以及这两个词的区别。

首先,存在错误——分为两种类型——语法错误和逻辑错误。当程序员未能遵循代码中特定实体的预定义语法规则时,就会发生语法错误。

如果编译器发现语法错误,它将终止程序并引发错误。我们需要修复它。

逻辑错误是程序员在代码逻辑中犯的错误。这些不会被引发;相反,当代码未能达到预期目的或解决问题时,需要理解这个错误。这些错误需要程序员搜索、查找和编辑,并且很难找到。

现在,让我们来谈谈异常这个概念:

异常是在执行期间(而不是编译时)引发的意外错误。 这些对代码没有危险;Python 中有处理这些异常的方法。

示例:如果我们尝试将一个数除以 0,编译器不会检测到它,因为语法是正确的。在执行期间,将引发异常。

代码

输出

Traceback (most recent call last):
  File "D:\Programs\python\exception_ex.py", line 2, in 
    print(a/0)
ZeroDivisionError: division by zero

正如你所观察到的,消息的最后一行指出了引发异常的类型。Python 中有许多内置异常。

“Exception”是所有异常的基类。Python 中定义了一个完整的异常层次结构。你可以在网上查找。

我们可以使用 try 和 except 块来处理异常。我们还可以引发用户定义的异常,这将在本文中进一步讨论。

使用 try 和 except 语句捕获异常

异常通常是意外发生的,会干扰整个代码的执行。因此,我们捕获这些异常并处理它们,以便代码能够顺利执行。

我们该如何做到这一点?

  • 程序员认为可能会导致异常的代码部分被放在 try 块中。
  • 如果这种担忧成真并发现了异常,我们将在“except”块中编写处理代码。
  • 这里发生的是,我们在“except”块中编写的代码将替换异常发生时通常会打印的异常/错误消息。
  • 这样,执行流程就不会被打断,异常也会得到处理。

语法

示例程序

让我们以前面的 Zero Division Error 发生的例子为例。

在输出中,将打印“except”块中的 print 语句,而不是异常。

发生了一个错误

# 如果我们尝试访问数组中的越界索引

通常,会引发ArrayIndexOutOfBounds 异常;让我们来处理它。

数组中没有索引 4,但我们尝试访问它——因此它会进入 except 块并打印该语句。

输出

Python 中有大量的内置异常。你可以在网上查找。

下表列出了一些常见的异常

Exception背景
1. ZeroDivisionError如果我们尝试执行除以 0 的操作
2. OverflowError如果操作结果太大而无法表示
3. IndexError如果我们尝试访问序列中无效的索引
4. AttributeError如果我们尝试调用一个属性(函数对象),而它的类型不受支持。
5. EOFError如果 Python 函数在完全未读取任何数据的情况下到达文件末尾。
6. KeyError如果我们尝试访问字典中无效或甚至不存在的键
7. IOError如果我们提供错误的文件名或不正确的位置。

这些错误也会在其他上下文中引发。

捕获特定异常(带有多个 except 语句的 try)

假设代码可能引发多个异常。程序员需要用不同的代码替换不同的异常,即如果他们想以不同的方式处理每个异常,也有这样的选项。

  • 一个 try 语句可以有多个 catch 语句。
  • 我们可以通过在 except 块中与 except 并列提及异常来捕获特定类型的异常。

语法

可以包含任意数量的 except 语句

这里有两个异常。假设我们注释掉第二个带有 Zero division error 的“for 循环”。将执行带有 index error 的“except”块,如果我们注释掉第一个带有 index error 的 for 循环,则执行带有 zero division error 的 except 块。

输出

# Zero division error
[2, 3, 5, 6]
0.6666666666666666
1.0
2.0
Oops! Division by zero
#Index error
[2, 3, 5, 6]
The element in 0 index is: 2
The element in 1 index is: 3
The element in 2 index is: 5
The element in 3 index is: 6
Tried to access an out of bound index-check it

带有 else 块的 try

我们可以将 try-except 块与 else 块一起使用。根据语法,else 块必须放在所有“except”块之后。如果 try 块中的代码成功执行而未引发任何异常,则执行 else 块。

示例程序

输出

#Sample output-1-No exception rose
Enter the numerator: 3
Enter the denominator: 4 
The result of the division: 0.75

#Sample output-2-Exception rose
Enter the numerator: 3
Enter the denominator: 0
The denominator cannot be zero

Python 中的“finally”关键字。

“finally”是 Python 中的一个关键字,我们可以使用它来处理异常,在 else 块(如果有)之后放置它,就像名字所暗示的那样。 finally 块中的代码将不考虑其他任何块而执行。

语法

示例程序

输出

[2, 3, 5, 6]
The element in 0 index is: 2
The element in 1 index is: 3
The element in 2 index is: 5
The element in 3 index is: 6
Tried to access an out of bound index-check it
You are now looking at the code in the finally block

在 Python 中引发我们自己的异常

raise”是 Python 中的一个关键字,通过使用 raise 语句,我们可以引发自己的异常以停止执行后续语句。

语法

示例程序片段

输出

Don't divide by zero-check it

这些通常用于创建我们自己的约束/异常。例如,如果用户输入不符合我们要求的格式,则引发异常等。

重要提示:“raise”语句如果没有参数无效,会引发错误

输出

Traceback (most recent call last):
  File "D:\Programs\python\Raise_exception.py", line 2, in 
    raise
RuntimeError: No active exception to reraise