Python 中的 Try Except 结构:异常处理详解
在 Python 编程中,try...except
语句是一种强大的工具,用于优雅地处理程序运行中可能出现的异常情况,从而避免程序意外崩溃。 异常处理能够显著提高代码的健壮性和可靠性,降低程序出现故障的风险。 本文将深入探讨异常处理机制,分析其适用场景,并介绍如何主动引发异常。
什么是异常处理?
异常是程序执行过程中发生的特殊情况,例如错误或意外事件。 如果这些异常没有被妥善处理,程序就会终止并报错。 因此,异常处理是一种捕获并处理这些异常的机制,确保程序在遇到问题时能够继续运行,或者至少能够以一种可控的方式停止。
以下示例演示了异常的产生:
user_input = input("请输入一个数字:")
num = int(user_input)
print("您输入的数字乘以 2 的结果是:", num * 2)
这段代码初看似乎没有问题。 它接收用户输入,将其转换为整数,然后输出该整数的两倍。
如果用户输入 5,程序将顺利执行,输出结果。
然而,如果用户输入的是字符串 “hello”,而不是数字,程序就会崩溃。 因为字符串 “hello” 不能被转换为整数,这将导致一个异常,从而导致程序停止运行。
为什么会引发异常?为什么要处理它们?
在编写代码时,我们通常会将程序拆分成多个函数。 这些函数相互调用,执行不同的任务。
在上面的示例中,我们调用了 input
函数来获取用户输入,然后调用 int
函数将字符串转换为整数,最后调用 print
函数来输出结果。
当函数执行其操作时,可能会遇到它无法处理的错误。 在这种情况下,函数需要停止执行并报告错误。 为了做到这一点,它会引发一个异常。
调用函数的代码负责监听这些异常并采取适当的措施。 如果不这样做,程序就会在遇到错误时崩溃,就像我们在前面的例子中看到的那样。
因此,异常实际上是一种通信机制,允许被调用的函数向调用它的代码发送求救信号。 响应这个信号,采取适当的措施,就是异常处理的本质。
不同类型的异常
重要的是要了解,并非所有异常都是相同的。 不同类型的错误会引发不同类型的异常。 例如,尝试将数字除以零会引发 ZeroDivisionError
。 尝试使用无效数据类型执行操作会引发 TypeError
。 这里有异常类型的完整列表。
如何处理异常
如前所述,异常是函数发出的求救信号。 我们的代码应该监听这些信号,并在收到信号时采取相应的行动。 为了正确处理异常,我们使用 Python 的 try...except
结构。 基本结构如下:
try:
# 尝试执行的代码
except:
# 如果发生异常,则执行此代码
finally:
# 无论是否发生异常,都会执行此代码
如您所见,该结构由三个关键字组成:
try
try
关键字标记 try...except
结构的开始,它同时也标记了可能引发异常的代码块。 它指示 Python 解释器尝试运行该代码块中的代码。 如果抛出异常,程序会立即停止并跳转到执行 except
代码块中的代码。
except
except
关键字标记在执行 try
代码块时抛出异常时将要执行的代码块。 您可以为不同类型的异常定义多个 except
代码块,稍后我们将对此进行说明。
finally
finally
关键字是 try...except
结构中使用的第三个也是最后一个关键字。 它标记了无论是否发生异常都将执行的代码块。
一个示例
以下是一个示例,演示了上述关键字如何处理异常。 我们将之前的示例修改为如下所示:
try:
user_input = input("请输入一个数字:")
num = int(user_input)
print("您输入的数字乘以 2 的结果是:", num * 2)
except:
print("发生了一些错误")
finally:
print("无论如何,这段代码都会被执行")
如果用户输入有效数字 5,您将看到以下结果:
如果输入 “hello”,您将看到以下结果:
因此,当在 try
代码块中执行代码时未引发异常时,计算机将跳转到 finally
代码块。 但是,当在 try
代码块中执行代码时引发异常时,计算机将跳转到 except
代码块,然后执行 finally
代码块。
您还可以处理特定类型的异常。 例如,如果您想以特定的方式处理 ValueError
和 KeyboardInterrupt
异常,您可以像这样修改上面的代码:
try:
user_input = input("请输入一个数字:")
num = int(user_input)
print("您输入的数字乘以 2 的结果是:", num * 2)
except ValueError:
print("值不能转换为整数")
except KeyboardInterrupt:
print("收到键盘中断")
except:
print("捕获所有异常的块")
finally:
print("无论如何,这段代码都会被执行")
在上面的代码中,我们有 3 个 except
代码块。 第一个 except
代码块仅捕获 ValueError
异常,而第二个块仅捕获 KeyboardInterrupt
异常。 最后一个 except
代码块没有要监听的关联异常类型。 因此,它捕获了前两个块未捕获的剩余异常。
运行上面的代码,你应该看到类似于这样的输出:
当发生异常时,您可以获取有关异常的更多信息。 您可以使用 as
关键字来访问异常对象。 其用法如下:
try:
user_input = input("请输入一个数字:")
num = int(user_input)
print("您输入的数字乘以 2 的结果是:", num * 2)
except ValueError as e:
print("ValueError:", e)
except KeyboardInterrupt as e:
print("KeyboardInterrupt:", e)
except Exception as e:
print("其他异常", e)
如何引发异常
到目前为止,我们一直在处理其他函数引发的异常。 但是,您也可以在代码中引发异常。 要引发异常,我们使用 raise
关键字。 我们还需要指定一个类来表示我们要引发的异常类型,以及一个与异常相关的、人类可读的消息。
在下面的示例中,我们使用 Exception
类引发一个通用异常。 然后,我们将消息传递给类的构造函数。
raise Exception('发生了一些错误')
如果您将上面的代码片段作为程序运行,您将获得类似如下的输出:
您还可以指定不同类型的异常。 例如,当值的数据类型错误时,您可以引发 TypeError
异常:
def double(x):
if isinstance(x, int):
return x * 2
else:
raise TypeError('x 应该是一个整数')
或者,如果指定的值超出可接受的范围,则可以引发 ValueError
:
def say_hello(name):
if name == '':
raise ValueError('值超出范围')
else:
print('你好', name)
您还可以通过继承 Exception
类来创建自己的异常类型。 这是一个例子:
class InvalidHTTPMethod(Exception):
pass
在上面的例子中,我们创建了一个继承自 Exception
类的 InvalidHTTPMethod
类。 我们可以像以前一样使用它来引发异常:
raise InvalidHTTPMethod('必须是 GET 或 POST 方法')
异常处理的常见应用场景
异常处理在许多场景中都有应用。 前面的示例展示了它如何处理由用户输入引起的异常。 本节将介绍另外两种可以使用异常处理的情况。 它们包括处理网络请求失败和读取文件时出现的异常。
发出网络请求
在下面的示例中,我们向 Google 发出请求。 我们监听异常以处理它们。 这些异常是在 requests.exceptions
对象中定义的。
import requests
try:
response = requests.get("https://google.com")
# 检查响应状态码是否在 200-299 范围内(成功响应)
if 200 <= response.status_code < 300:
print("请求成功!")
else:
print(f"请求失败,状态码为:{response.status_code}")
except requests.exceptions.RequestException as e:
print(f"RequestException 发生:{e}")
except requests.exceptions.ConnectionError as e:
print(f"ConnectionError 发生:{e}")
except requests.exceptions.Timeout as e:
print(f"Timeout 发生:{e}")
except requests.exceptions.TooManyRedirects as e:
print(f"TooManyRedirects 发生:{e}")
except requests.exceptions.HTTPError as e:
print(f"HTTPError 发生:{e}")
except Exception as e:
print(f"发生意外错误:{e}")
从文件中读取数据
在最后一个示例中,我们从 hello.txt
文件读取数据。 我们还处理可能引发的常见异常,例如 FileNotFound
错误和 IOError
。
try:
with open(file_path, 'r') as file:
data = file.read()
print("文件内容:")
print(data)
except FileNotFoundError as e:
print(f"FileNotFoundError 发生:{e}")
except IOError as e:
print(f"IOError 发生:{e}")
except Exception as e:
print(f"发生意外错误:{e}")
结论
本文探讨了异常是什么以及为什么会引发异常。 我们还认识到处理异常是为了提高代码的可靠性并防止崩溃。 最后,我们介绍了如何处理异常以及如何引发异常。
接下来,请查看常见的 Python 错误类型以及如何解决它们。