原文: https://www.programiz.com/python-programming/exception-handling

在本教程中,您将在示例的帮助下使用tryexceptfinally语句学习如何在 Python 程序中处理异常。

Python 异常

Python 有许多内置异常,这些异常在您的程序遇到错误(程序中的某些地方出错)时引发。

当发生这些异常时,Python 解释器将停止当前进程并将其传递给调用进程,直到对其进行处理。 如果不处理,程序将崩溃。

例如,让我们考虑一个程序,其中有一个函数 A,该函数调用函数B,该函数又调用函数C。 如果异常在函数C中发生,但未在C中处理,则该异常传递给B,然后传递给A

如果从未处理过,则会显示一条错误消息,并且我们的程序突然突然中止。


在 Python 中捕捉异常

在 Python 中,可以使用try语句处理异常。

可能引发异常的关键操作放在try子句中。 处理异常的代码写在except子句中。

因此,一旦捕获到异常,我们可以选择要执行的操作。 这是一个简单的例子。

  1. # import module sys to get the type of exception
  2. import sys
  3. randomList = ['a', 0, 2]
  4. for entry in randomList:
  5. try:
  6. print("The entry is", entry)
  7. r = 1/int(entry)
  8. break
  9. except:
  10. print("Oops!", sys.exc_info()[0], "occurred.")
  11. print("Next entry.")
  12. print()
  13. print("The reciprocal of", entry, "is", r)

输出

  1. The entry is a
  2. Oops! <class 'ValueError'> occurred.
  3. Next entry.
  4. The entry is 0
  5. Oops! <class 'ZeroDivisionError'> occured.
  6. Next entry.
  7. The entry is 2
  8. The reciprocal of 2 is 0.5

在此程序中,我们遍历randomList列表的值。 如前所述,可能导致异常的部分位于try块内。

如果没有异常,则跳过except块,继续正常流程(最后一个值)。 但是,如果发生任何异常,它将被except块(第一个和第二个值)捕获。

在这里,我们使用sys模块内的exc_info()函数打印异常的名称。 我们可以看到a导致ValueError0导致ZeroDivisionError

由于 Python 中的每个异常都继承自基本Exception类,因此我们还可以通过以下方式执行上述任务:

  1. # import module sys to get the type of exception
  2. import sys
  3. randomList = ['a', 0, 2]
  4. for entry in randomList:
  5. try:
  6. print("The entry is", entry)
  7. r = 1/int(entry)
  8. break
  9. except Exception as e:
  10. print("Oops!", e.__class__, "occurred.")
  11. print("Next entry.")
  12. print()
  13. print("The reciprocal of", entry, "is", r)

该程序具有与上述程序相同的输出。


捕获 Python 中的特定异常

在上面的示例中,我们没有在except子句中提及任何特定的异常。

这不是一个好的编程习惯,因为它将捕获所有异常并以相同的方式处理每种情况。 我们可以指定except子句应捕获的异常。

一个try子句可以具有任意数量的except子句来处理不同的异常,但是,如果发生异常,则仅执行一个子句。

我们可以使用值的元组在except子句中指定多个异常。 这是示例伪代码。

  1. try:
  2. # do something
  3. pass
  4. except ValueError:
  5. # handle ValueError exception
  6. pass
  7. except (TypeError, ZeroDivisionError):
  8. # handle multiple exceptions
  9. # TypeError and ZeroDivisionError
  10. pass
  11. except:
  12. # handle all other exceptions
  13. pass

在 Python 中引发异常

在 Python 编程中,在运行时发生错误时会引发异常。 我们还可以使用raise关键字手动引发异常。

我们可以选择将值传递给异常,以阐明引发该异常的原因。

  1. >>> raise KeyboardInterrupt
  2. Traceback (most recent call last):
  3. ...
  4. KeyboardInterrupt
  5. >>> raise MemoryError("This is an argument")
  6. Traceback (most recent call last):
  7. ...
  8. MemoryError: This is an argument
  9. >>> try:
  10. ... a = int(input("Enter a positive integer: "))
  11. ... if a <= 0:
  12. ... raise ValueError("That is not a positive number!")
  13. ... except ValueError as ve:
  14. ... print(ve)
  15. ...
  16. Enter a positive integer: -2
  17. That is not a positive number!

Python try-else子句

在某些情况下,如果try中的代码块运行无误,则可能要运行某个代码块。 对于这些情况,可以在try语句中使用可选的else关键字。

注意else子句不会处理else子句中的异常。

让我们看一个例子:

  1. # program to print the reciprocal of even numbers
  2. try:
  3. num = int(input("Enter a number: "))
  4. assert num % 2 == 0
  5. except:
  6. print("Not an even number!")
  7. else:
  8. reciprocal = 1/num
  9. print(reciprocal)

输出

如果我们传递一个奇数:

  1. Enter a number: 1
  2. Not an even number!

如果我们传递一个偶数,则将计算并显示倒数。

  1. Enter a number: 4
  2. 0.25

但是,如果传递 0,则会得到ZeroDivisionError,因为else内部的代码块未由前面的except处理。

  1. Enter a number: 0
  2. Traceback (most recent call last):
  3. File "<string>", line 7, in <module>
  4. reciprocal = 1/num
  5. ZeroDivisionError: division by zero

Python try-finally

Python 中的try语句可以具有可选的finally子句。 该子句无论如何执行,通常用于释放外部资源。

例如,我们可能通过网络或使用文件或图形用户界面(GUI)连接到远程数据中心。

在所有这些情况下,无论程序是否成功运行,我们都必须在程序停止之前清理资源。 这些操作(关闭文件,GUI 或与网络断开连接)在finally子句中执行,以确保执行。

这是文件操作的示例来说明这一点。

  1. try:
  2. f = open("test.txt",encoding = 'utf-8')
  3. # perform file operations
  4. finally:
  5. f.close()

这种类型的构造可确保即使在程序执行期间发生异常,也可以关闭文件。