Python 的异常处理机制通过 try、except、else 和 finally 语句来捕获和处理运行时异常。了解如何捕获异常、如何传递异常以及如何自定义异常类是 Python 异常处理的关键。下面详细介绍 Python 异常的捕获和传递。
1. 捕获异常 (Exception Handling)
1.1 基本的异常捕获
使用 try...except
语句可以捕获并处理程序运行时可能发生的异常。捕获到异常后,可以在 except
块中执行相应的处理逻辑。
try:
x = 10 / 0 # 会抛出除零错误
except ZeroDivisionError as e:
print(f"捕获到异常:{e}") # 捕获并处理 ZeroDivisionError
1.2 捕获多个异常
一个 try
块中可以捕获多种类型的异常,具体的异常类型需要在不同的 except
语句中进行处理。
try:
# 假设这里可能会引发 ValueError 或 ZeroDivisionError
x = int("abc") # 会抛出 ValueError
y = 10 / 0 # 会抛出 ZeroDivisionError
except ValueError as e:
print(f"ValueError 异常:{e}")
except ZeroDivisionError as e:
print(f"ZeroDivisionError 异常:{e}")
1.3 捕获所有异常
如果需要捕获所有异常类型,可以使用 Exception
类(所有异常的基类)来捕获。
try:
# 可能会抛出任何异常
x = 10 / 0
except Exception as e:
print(f"捕获到异常:{e}")
1.4 使用 else
子句
else
子句是 try...except
语句的一部分,它会在没有异常发生时执行。如果 try
块中的代码没有引发异常,则会执行 else
中的代码。
try:
x = 10 / 2 # 没有异常
except ZeroDivisionError as e:
print(f"捕获到异常:{e}")
else:
print(f"计算结果是:{x}")
1.5 使用 finally
子句
finally
块用于在异常发生与否时,执行一些资源清理工作,如关闭文件、数据库连接等。无论是否发生异常,finally
块的内容都会执行。
try:
f = open("test.txt", "r")
content = f.read()
except FileNotFoundError as e:
print(f"文件未找到:{e}")
else:
print(content)
finally:
f.close() # 无论是否发生异常,都确保文件关闭
2. 异常的传递 (Exception Propagation)
2.1 异常向上传递
当 try
块中的代码引发异常后,如果异常没有被当前函数处理,它会向上层函数传播。直到遇到处理该异常的 except
块或程序终止。
def func1():
print("In func1")
raise ValueError("Error in func1")
def func2():
print("In func2")
func1()
try:
func2()
except ValueError as e:
print(f"捕获到异常:{e}")
输出:
In func2
In func1
捕获到异常:Error in func1
2.2 自定义异常
你可以自定义异常类并在代码中抛出自定义异常。自定义异常通常用于表示程序中的特定错误类型。
class MyError(Exception):
pass
def func():
raise MyError("这是自定义异常")
try:
func()
except MyError as e:
print(f"捕获到自定义异常:{e}")
2.3 异常链 (Exception Chaining)
有时我们需要在捕获某个异常后抛出一个新的异常,并将原始异常信息保留。使用 raise ... from
可以在抛出新异常时保留原始异常。
def func1():
raise ValueError("这是原始异常")
def func2():
try:
func1()
except ValueError as e:
raise RuntimeError("这是新的异常") from e # 保留原始异常
try:
func2()
except RuntimeError as e:
print(f"捕获到异常:{e}")
print(f"原始异常:{e.__cause__}")
输出:
捕获到异常:这是新的异常
原始异常:这是原始异常
3. 抛出异常 (Raising Exceptions)
有时你可能希望主动抛出异常,以便让调用方捕获和处理。你可以使用 raise
关键字手动抛出异常。
def check_age(age):
if age < 18:
raise ValueError("年龄必须大于或等于18")
return f"年龄 {age} 合法"
try:
print(check_age(16))
except ValueError as e:
print(f"捕获到异常:{e}")
4. 总结
- 捕获异常:使用
try...except
语句来捕获异常,except
块用于处理捕获到的异常。- 异常的传递:当一个异常没有被当前函数捕获时,它会向调用堆栈中上层的函数传递,直到捕获到该异常。
- 异常链:使用
raise ... from
可以在抛出新异常时保留原始异常信息,帮助跟踪错误发生的根本原因。- 抛出异常:使用
raise
可以显式地抛出异常,并且可以在适当的时机传递异常信息给调用方。