使用 try except 处理 Python 异常

PythonBeginner
立即练习

介绍

在这个实验中,你将学习如何使用 try...except 语句有效地处理 Python 中的异常。我们将探讨如何捕获特定的异常,如 ValueError,处理多种异常类型,以及如何使用 elsefinally 块来更好地控制程序的流程。你还将学习如何抛出自定义异常,以便在代码中指示特定的错误情况。通过实践练习,你将获得编写健壮且容错的 Python 程序的实际经验。

这是一个实验(Guided Lab),提供逐步指导来帮助你学习和实践。请仔细按照说明完成每个步骤,获得实际操作经验。根据历史数据,这是一个 初级 级别的实验,完成率为 100%。获得了学习者 100% 的好评率。

使用 try except 处理 ValueError

在这一步,你将学习如何使用 try...except 语句来处理 ValueError。当一个函数接收到类型正确但值不合适的参数时,就会发生 ValueError。一个常见的例子是尝试使用 int() 函数将一个不是数字的字符串转换为整数。

我们将编写一个 Python 脚本,提示用户输入一个整数。如果输入不是一个有效的整数,我们将捕获 ValueError 并显示一条用户友好的消息。

在左侧的 WebIDE 文件浏览器中,找到并打开位于 ~/project 目录下的 handle_value_error.py 文件。然后,向其中添加以下代码:

while True:
    try:
        x = int(input('Please enter an integer: '))
        print(f'You entered: {x}')
        break
    except ValueError:
        print('That was not a valid integer. Please try again.')

保存文件。

现在,打开集成终端并使用 python 命令运行该脚本:

python ~/project/handle_value_error.py

脚本会提示你输入一个整数。首先,尝试输入一个非整数值,如 hello,以查看错误处理的实际效果。然后,输入一个有效的整数,如 123,以查看成功的执行路径。

示例输出:

Please enter an integer: hello
That was not a valid integer. Please try again.
Please enter an integer: 123
You entered: 123

在这段代码中:

  • while True: 循环确保程序会持续要求输入,直到输入了一个有效的整数为止。
  • try 块包含可能引发异常的代码,特别是 int(input(...)) 调用。
  • 如果在 try 块中发生了 ValueError,则执行 except ValueError: 块中的代码。
  • 如果没有发生异常,则执行 print() 语句,然后 break 退出循环。

这演示了 try...except ValueError 如何让你能够优雅地处理无效输入,而不会导致程序崩溃。

处理多个异常

一段代码可能会引发不同类型的异常。Python 允许你使用多个 except 子句或在一个 except 子句中将异常分组来处理多个异常。

我们来编写一个执行除法的脚本。如果输入不是数字,此操作可能会引发 ValueError;如果除数为零,则会引发 ZeroDivisionError

在 WebIDE 中,打开文件 ~/project/handle_multiple_exceptions.py 并添加以下代码。此版本为每种错误类型使用了单独的 except 块。

try:
    numerator = int(input("Enter the numerator: "))
    denominator = int(input("Enter the denominator: "))
    result = numerator / denominator
    print(f"Result: {result}")
except ValueError:
    print("Invalid input. Please enter integers only.")
except ZeroDivisionError:
    print("Error: Division by zero is not allowed.")

保存文件并从终端运行它:

python ~/project/handle_multiple_exceptions.py

使用不同的输入测试脚本以触发每个异常:

  1. 输入一个非整数值(例如,abc)。
  2. 为分母输入 0
  3. 为两者都输入有效的整数。

除以零的示例输出:

Enter the numerator: 10
Enter the denominator: 0
Error: Division by zero is not allowed.

你也可以通过在元组(tuple)中分组异常,使用单个 except 子句来处理多个异常。这在对不同错误执行相同操作时非常有用。

现在,更新 ~/project/handle_multiple_exceptions.py 中的代码以使用这种分组方法:

try:
    numerator = int(input("Enter the numerator: "))
    denominator = int(input("Enter the denominator: "))
    result = numerator / denominator
    print(f"Result: {result}")
except (ValueError, ZeroDivisionError):
    print("An error occurred: Invalid input or division by zero.")

保存文件并使用相同的测试用例再次运行它,以观察新的、合并的错误消息。

使用 else 子句执行代码

try 语句可以包含一个可选的 else 子句。只有当 try 块成功执行完毕而没有引发任何异常时,else 块中的代码才会被执行。这对于将应在成功时运行的代码与主要的 try 块分离开来很有用。

让我们修改除法脚本以包含一个 else 块。

在 WebIDE 中,打开文件 ~/project/try_except_else.py 并添加以下代码:

try:
    numerator = int(input("Enter the numerator: "))
    denominator = int(input("Enter the denominator: "))
    result = numerator / denominator
except (ValueError, ZeroDivisionError):
    print("An error occurred: Invalid input or division by zero.")
else:
    print("Division successful!")
    print(f"Result: {result}")

保存文件并从终端运行它:

python ~/project/try_except_else.py

使用会失败和会成功的输入来测试脚本:

  1. 为分母输入 0 以触发异常。
  2. 输入有效的、非零的整数以执行 else 块。

示例输出:

Enter the numerator: 10
Enter the denominator: 0
An error occurred: Invalid input or division by zero.
Enter the numerator: 10
Enter the denominator: 2
Division successful!
Result: 5.0

正如你所见,只有在除法成功时,才会打印 else 块中的消息。如果发生异常,则执行 except 块,并跳过 else 块。

使用 finally 子句确保代码执行

try 语句还有一个可选的 finally 子句。无论 try 块中是否发生异常,finally 块中的代码都总是会被执行。这使得它非常适合用于清理操作,例如关闭文件或释放资源,这些操作在所有情况下都必须发生。

让我们向除法示例添加一个 finally 块。

在 WebIDE 中,打开文件 ~/project/try_except_finally.py 并添加以下代码:

try:
    numerator = int(input("Enter the numerator: "))
    denominator = int(input("Enter the denominator: "))
    result = numerator / denominator
    print(f"Result: {result}")
except (ValueError, ZeroDivisionError):
    print("An error occurred: Invalid input or division by zero.")
finally:
    print("Execution finished.")

保存文件并从终端运行它:

python ~/project/try_except_finally.py

使用会失败和会成功的输入来运行脚本:

  1. 为分母输入 0 以触发异常。
  2. 输入有效的、非零的整数。

示例输出:

Enter the numerator: 10
Enter the denominator: 0
An error occurred: Invalid input or division by zero.
Execution finished.
Enter the numerator: 10
Enter the denominator: 2
Result: 5.0
Execution finished.

请注意,来自 finally 块的消息 "Execution finished." 在两种情况下都会被打印出来。finally 块保证会执行,使其成为放置必要清理代码的可靠位置。

引发自定义异常

有时你需要 сигнализировать(发出信号)一个不是内置 Python 异常的错误条件。你可以使用 raise 语句来实现这一点,它允许你创建和触发自己的异常。这对于使你应用程序的错误处理更具体和更具描述性非常有用。

首先,我们来看看如何 raise 一个内置异常。在 WebIDE 中,打开文件 ~/project/raise_exception.py 并添加以下代码:

def check_positive(number):
    if number <= 0:
        raise ValueError("Input must be a positive number")
    print(f"The number {number} is positive.")

try:
    check_positive(-5)
except ValueError as e:
    print(f"Caught an exception: {e}")

try:
    check_positive(10)
except ValueError as e:
    print(f"Caught an exception: {e}")

保存文件并从终端运行它:

python ~/project/raise_exception.py

输出将是:

Caught an exception: Input must be a positive number
The number 10 is positive.

在这里,如果输入不是正数,check_positive 函数会抛出一个 ValueError,然后被 except 块捕获。

现在,我们定义并抛出一个自定义异常。自定义异常是继承自内置 Exception 类的类。

在 WebIDE 中,打开文件 ~/project/custom_exception.py 并添加以下代码:

class NegativeNumberError(Exception):
    """Custom exception raised for negative numbers."""
    pass

def process_positive_number(number):
    if number < 0:
        raise NegativeNumberError("Negative numbers are not allowed")
    print(f"Processing positive number: {number}")

try:
    process_positive_number(-10)
except NegativeNumberError as e:
    print(f"Caught custom exception: {e}")

try:
    process_positive_number(20)
except NegativeNumberError as e:
    print(f"Caught custom exception: {e}")

保存文件并从终端运行它:

python ~/project/custom_exception.py

输出将是:

Caught custom exception: Negative numbers are not allowed
Processing positive number: 20

在这个例子中,我们定义了自己的 NegativeNumberError 并在特定条件下抛出了它。然后 try...except 块专门捕获了这个自定义错误类型,使得错误处理更加精确。

总结

在这个实验(Lab)中,你学习了如何在 Python 中实现健壮的错误处理。你首先使用 try...except 块来捕获用户输入中特定的 ValueError。然后,你通过分别处理多种异常类型或在单个块中处理它们来扩展了这一知识。你还学会了使用 else 子句仅在没有发生异常时运行代码,以及使用 finally 子句在所有情况下执行清理代码。最后,你练习了创建和抛出自定义异常来处理特定于应用程序的错误,使你的代码更具可读性和可维护性。