介绍
在这个实验中,你将学习如何使用不同的技术来检查 Python 中是否捕获到了异常。本实验聚焦于异常处理,这是编写健壮且可靠的 Python 代码的关键环节。
本实验将引导你理解如何使用 try...except 块来处理异常,从而优雅地处理像 ZeroDivisionError 这样的错误。你将学习如何在 except 块中设置一个标志,以表明已经捕获到了异常。最后,本实验将介绍使用上下文管理器进行更可控的异常处理的概念。
学习异常处理流程
在这一步中,你将学习 Python 中的异常处理。异常处理是编写健壮且可靠代码的关键部分。它使你能够优雅地处理程序执行过程中可能出现的错误,防止程序崩溃,并提供更友好的用户体验。
让我们从一个简单的例子开始。假设你要对两个数字进行除法运算,但第二个数字可能为零。在 Python 中,除以零是未定义的操作,会引发 ZeroDivisionError 异常。
在 LabEx 环境中打开 VS Code 编辑器。
在
~/project目录下创建一个名为division.py的新文件。touch ~/project/division.py编辑
division.py文件,并添加以下代码:## division.py numerator = 10 denominator = 0 result = numerator / denominator print(result)使用
python命令运行脚本:python ~/project/division.py
你会看到类似如下的错误信息:
Traceback (most recent call last):
File "/home/labex/project/division.py", line 4, in <module>
result = numerator / denominator
ZeroDivisionError: division by zero
此错误信息表明,由于我们试图除以零,引发了 ZeroDivisionError 异常。如果没有异常处理,程序会突然终止。
现在,让我们使用异常处理来优雅地处理这个错误。
修改
division.py文件,加入try...except块:## division.py numerator = 10 denominator = 0 try: result = numerator / denominator print(result) except ZeroDivisionError: print("Error: Cannot divide by zero.")在这段代码中,
try块包含了可能引发异常的代码。如果在try块中出现ZeroDivisionError异常,except块中的代码将被执行。再次运行脚本:
python ~/project/division.py
现在,程序不会崩溃,而是会输出:
Error: Cannot divide by zero.
这展示了异常处理的基本结构:
try块包含可能引发异常的代码。except块指定要捕获的异常类型,以及当该异常发生时要执行的代码。
你还可以使用多个 except 块来捕获多种类型的异常:
## division.py
numerator = 10
denominator = "abc"
try:
result = numerator / int(denominator)
print(result)
except ZeroDivisionError:
print("Error: Cannot divide by zero.")
except ValueError:
print("Error: Invalid input. Please enter a number.")
在这个例子中,我们添加了一个 ValueError 异常处理程序。如果 denominator 无法转换为整数(例如,它是像 "abc" 这样的字符串),就会引发 ValueError 异常,相应的 except 块将被执行。
运行脚本:
python ~/project/division.py
输出:
Error: Invalid input. Please enter a number.
通过预测和处理潜在的错误,异常处理使你能够编写更健壮、更友好的程序。
在 except 块中设置标志
在这一步中,你将学习如何在 except 块中使用标志,根据是否发生异常来控制程序的流程。当你需要根据 try 块的执行结果执行不同的操作时,这是一种很有用的技术。
基于上一个示例,假设你想计算一个数的倒数,但前提是除法运算成功。你可以使用一个标志来指示除法是否成功,然后相应地计算倒数。
在 LabEx 环境中打开 VS Code 编辑器。
修改
~/project目录下的division.py文件,加入一个标志:## division.py numerator = 10 denominator = 2 success = True ## 初始化标志为 True try: result = numerator / denominator print("Result of division:", result) except ZeroDivisionError: print("Error: Cannot divide by zero.") success = False ## 如果发生错误,将标志设置为 False except ValueError: print("Error: Invalid input. Please enter a number.") success = False ## 如果发生错误,将标志设置为 False else: print("No exception occurred.") if success: try: reciprocal = 1 / result print("Reciprocal:", reciprocal) except ZeroDivisionError: print("Cannot calculate reciprocal of zero.") else: print("Reciprocal calculation skipped due to error.")在这段代码中:
- 我们在
try块之前将一个名为success的标志初始化为True。 - 如果发生
ZeroDivisionError或ValueError异常,我们会在相应的except块中将success标志设置为False。 - 在
try...except块之后,我们检查success标志的值。如果它仍然为True,则表示没有发生异常,我们可以安全地计算倒数。否则,我们跳过倒数的计算。 - 我们还添加了一个
else块,如果try块中没有发生异常,该块将被执行。
- 我们在
使用有效的分母运行脚本:
python ~/project/division.py输出:
Result of division: 5.0 No exception occurred. Reciprocal: 0.2现在,将
denominator改为0,然后再次运行脚本:## division.py numerator = 10 denominator = 0 ## 将分母改为 0 success = True try: result = numerator / denominator print("Result of division:", result) except ZeroDivisionError: print("Error: Cannot divide by zero.") success = False except ValueError: print("Error: Invalid input. Please enter a number.") success = False else: print("No exception occurred.") if success: try: reciprocal = 1 / result print("Reciprocal:", reciprocal) except ZeroDivisionError: print("Cannot calculate reciprocal of zero.") else: print("Reciprocal calculation skipped due to error.")运行脚本:
python ~/project/division.py输出:
Error: Cannot divide by zero. Reciprocal calculation skipped due to error.
这展示了你如何在 except 块中使用标志来控制程序的流程,并根据是否发生异常执行不同的操作。
使用上下文管理器进行控制
在这一步中,你将学习如何在 Python 中使用上下文管理器来简化异常处理,并确保即使发生异常,资源也能得到妥善管理。上下文管理器在处理文件、网络连接和其他需要显式关闭或释放的资源时特别有用。
上下文管理器是定义了 __enter__ 和 __exit__ 方法的对象。with 语句用于在上下文管理器的上下文中执行一段代码。当进入 with 块时,会调用 __enter__ 方法;当退出 with 块时,无论是否发生异常,都会调用 __exit__ 方法。
让我们从一个使用上下文管理器读取文件的简单示例开始。
在 LabEx 环境中打开 VS Code 编辑器。
在
~/project目录下创建一个名为file_handling.py的新文件。touch ~/project/file_handling.py编辑
file_handling.py文件,并添加以下代码:## file_handling.py filename = "my_file.txt" try: with open(filename, "w") as f: f.write("Hello, LabEx!\n") f.write("This is a test file.\n") except IOError as e: print(f"An I/O error occurred: {e}") try: with open(filename, "r") as f: content = f.read() print("File content:") print(content) except FileNotFoundError: print(f"The file '{filename}' was not found.") except IOError as e: print(f"An I/O error occurred: {e}")在这段代码中:
- 我们使用
with open(filename, "w") as f:语句以写入模式 ("w") 打开文件my_file.txt。open()函数返回一个文件对象,并将其赋值给变量f。 with语句确保即使发生异常,在退出代码块时文件也会自动关闭。- 我们使用
f.write()方法向文件写入两行文本。 - 然后,我们使用
with open(filename, "r") as f:语句以读取模式 ("r") 打开同一个文件。 - 我们使用
f.read()方法读取文件的全部内容,并将其打印到控制台。 - 我们将文件操作封装在
try...except块中,以处理可能出现的FileNotFoundError和IOError异常。
- 我们使用
运行脚本:
python ~/project/file_handling.py输出:
File content: Hello, LabEx! This is a test file.如果文件
my_file.txt不存在,脚本将创建该文件并写入指定的内容。如果文件已经存在,其内容将被覆盖。无论哪种情况,with语句都能确保文件被正确关闭。
让我们考虑另一个在文件处理过程中可能发生异常的示例:
## file_handling.py
filename = "my_file.txt"
try:
with open(filename, "r") as f:
for line in f:
## Simulate an error during processing
if "test" in line:
raise ValueError("Simulated error during processing")
print("Line:", line.strip())
except FileNotFoundError:
print(f"The file '{filename}' was not found.")
except ValueError as e:
print(f"A value error occurred: {e}")
except IOError as e:
print(f"An I/O error occurred: {e}")
在这个示例中,如果某一行包含单词 "test",我们通过抛出 ValueError 来模拟一个错误。即使发生此错误,with 语句也能确保文件被正确关闭。
运行脚本:
python ~/project/file_handling.py
输出:
Line: Hello, LabEx!
A value error occurred: Simulated error during processing
上下文管理器为 Python 中的资源管理和异常处理提供了一种简洁可靠的方式。它们确保即使发生错误,资源也能得到正确释放,使你的代码更健壮、更易于维护。
总结
在本次实验中,你首先学习了 Python 中的异常处理,这是编写健壮代码的一项关键技术。你从一个简单的除法示例开始,当除以零时会引发 ZeroDivisionError,导致程序终止。然后,你实现了一个 try...except 块来优雅地处理 ZeroDivisionError,防止程序崩溃,并输出一条有信息价值的错误消息。



