Python 中的异常及继承关系
在 Python 中,异常用于表示程序在运行过程中遇到的错误,所有异常类最终都继承自 BaseException
。通过异常处理,我们可以捕获和处理这些错误,避免程序崩溃。
Python 异常继承关系图
BaseException
+-- SystemExit
+-- KeyboardInterrupt
+-- GeneratorExit
+-- Exception
+-- StopIteration
+-- StopAsyncIteration
+-- ArithmeticError
| +-- FloatingPointError
| +-- OverflowError
| +-- ZeroDivisionError
+-- AssertionError
+-- AttributeError
+-- BufferError
+-- EOFError
+-- ImportError
| +-- ModuleNotFoundError
+-- LookupError
| +-- IndexError
| +-- KeyError
+-- MemoryError
+-- NameError
| +-- UnboundLocalError
+-- OSError
| +-- BlockingIOError
| +-- ChildProcessError
| +-- ConnectionError
| | +-- BrokenPipeError
| | +-- ConnectionAbortedError
| | +-- ConnectionRefusedError
| | +-- ConnectionResetError
| +-- FileExistsError
| +-- FileNotFoundError
| +-- InterruptedError
| +-- IsADirectoryError
| +-- NotADirectoryError
| +-- PermissionError
| +-- ProcessLookupError
| +-- TimeoutError
+-- ReferenceError
+-- RuntimeError
| +-- NotImplementedError
| +-- RecursionError
+-- SyntaxError
| +-- IndentationError
| +-- TabError
+-- SystemError
+-- TypeError
+-- ValueError
| +-- UnicodeError
| +-- UnicodeDecodeError
| +-- UnicodeEncodeError
| +-- UnicodeTranslateError
+-- Warning
+-- DeprecationWarning
+-- PendingDeprecationWarning
+-- RuntimeWarning
+-- SyntaxWarning
+-- UserWarning
+-- FutureWarning
+-- ImportWarning
+-- UnicodeWarning
+-- BytesWarning
+-- EncodingWarning
+-- ResourceWarning
1. BaseException
类
BaseException
是所有异常的基类,所有 Python 异常都从它继承。通常,不建议直接捕获 BaseException
,而应捕获其子类。
1.1 SystemExit
(不建议捕获)
- 说明:当调用
sys.exit()
以退出程序时,抛出此异常。 - 捕获建议:不建议捕获,因为它表示程序要正常退出。
- 示例:
import sys
try:
sys.exit()
except SystemExit:
print("程序退出")
1.2 KeyboardInterrupt
(不建议捕获)
- 说明:当用户按下
Ctrl+C
终止程序时,会抛出此异常。 - 捕获建议:可以捕获,但通常用于自定义处理程序中断。
- 示例:
try:
while True:
pass
except KeyboardInterrupt:
print("用户中断程序")
1.3 GeneratorExit
(不建议捕获)
- 说明:当生成器关闭时抛出,通常在
yield
生成器对象调用close()
时触发。 - 捕获建议:不建议捕获,通常由系统自动处理。
- 示例:
def my_generator():
try:
yield 1
finally:
print("生成器关闭")
gen = my_generator()
next(gen)
gen.close()
2. Exception
类(可以捕获)
Exception
是用户代码中常见异常的基类,大部分可捕获的异常都继承自它。
2.1 StopIteration
和 StopAsyncIteration
- 说明:当迭代器或异步迭代器到达结尾时抛出,通常由
for
循环隐式捕获。 - 捕获建议:一般不需要手动捕获。
示例:
my_iter = iter([1, 2, 3])
try:
while True:
print(next(my_iter))
except StopIteration:
print("迭代结束")
2.2 ArithmeticError
及其子类
- 说明:算术运算错误的基类。
- 捕获建议:可以捕获,用于处理算术错误。
ZeroDivisionError
- 说明:除数为零时抛出。
- 示例:
try:
result = 1 / 0
except ZeroDivisionError:
print("不能除以零")
OverflowError
- 说明:当数值运算结果超出表示范围时抛出。
FloatingPointError
- 说明:浮点运算出错时抛出,较少见。
2.3 AssertionError
- 说明:断言语句失败时抛出。
- 捕获建议:可以通过
try-except
捕获,但应谨慎使用断言。
示例:
try:
assert 1 == 2
except AssertionError:
print("断言失败")
2.4 AttributeError
- 说明:尝试访问对象不存在的属性时抛出。
示例:
try:
obj = None
obj.some_method()
except AttributeError:
print("对象没有这个属性")
2.5 BufferError
- 说明:缓冲区操作失败时抛出。
- 捕获建议:适用于处理低级别内存操作错误。
2.6 EOFError
- 说明:当读取到文件末尾但无法返回任何数据时抛出。
- 捕获建议:适用于文件或输入流操作。
2.7 ImportError
及其子类
- 说明:导入模块失败时抛出。
ModuleNotFoundError
- 说明:模块未找到时抛出。
示例:
try:
import non_existent_module
except ImportError:
print("模块导入失败")
2.8 LookupError
及其子类
- 说明:查找操作失败时的基类。
IndexError
- 说明:列表、元组或其他序列访问越界时抛出。
KeyError
- 说明:字典中查找不存在的键时抛出。
示例:
my_dict = {"name": "Alice"}
try:
print(my_dict["age"])
except KeyError:
print("键不存在")
2.9 MemoryError
- 说明:内存不足时抛出。
2.10 NameError
及其子类
- 说明:当尝试访问未定义的变量时抛出。
UnboundLocalError
- 说明:在函数中使用尚未赋值的局部变量时抛出。
示例:
try:
print(undefined_var)
except NameError:
print("变量未定义")
2.11 OSError
及其子类
- 说明:系统相关的错误,例如文件和网络操作失败。
- 捕获建议:适用于文件系统、网络等 I/O 操作。
常见子类:
FileNotFoundError
:文件未找到。PermissionError
:权限不足。TimeoutError
:操作超时。
示例:
try:
with open("non_existent_file.txt", "r") as f:
pass
except FileNotFoundError:
print("文件未找到")
2.12 ReferenceError
- 说明:弱引用被垃圾回收后访问无效对象时抛出。
2.13 RuntimeError
及其子类
- 说明:运行时错误的基类。
NotImplementedError
- 说明:尚未实现的方法抛出此异常。
2.14 SyntaxError
及其子类
- 说明:Python 语法错误时抛出。
IndentationError
- 说明:缩进错误。
TabError
- 说明:混合使用空格和 Tab 导致的错误。
2.15 TypeError
- 说明:操作或函数应用于不适当类型时抛出。
示例:
try:
print(1 + "a")
except TypeError:
print("类型错误")
2.16 ValueError
及其子类
- 说明:操作或函数接收到具有正确
类型但不合理的参数时抛出。
UnicodeError
及其子类
- 说明:与 Unicode 编码相关的错误。
3. Warning
类及其子类(可以捕获)
- 说明:
Warning
类表示非致命错误,通常用于提示潜在问题,不会中断程序的执行。尽管它们不会自动抛出,但可以通过warnings
模块生成和捕获警告。 - 捕获建议:可以捕获,通过
warnings.catch_warnings()
实现对警告的捕获。
常见子类:
DeprecationWarning
:提示某个功能即将被废弃。PendingDeprecationWarning
:类似DeprecationWarning
,但仅用于将来废弃的功能。RuntimeWarning
:运行时的一般警告。SyntaxWarning
:语法问题的警告。UserWarning
:用户代码产生的警告。FutureWarning
:将来版本会改变行为的警告。ImportWarning
:导入模块时发生问题的警告。UnicodeWarning
:Unicode 相关问题的警告。BytesWarning
:字节相关问题的警告。EncodingWarning
:编码相关问题的警告。ResourceWarning
:资源管理问题的警告(例如文件没有正确关闭)。
示例:
import warnings
def deprecated_function():
warnings.warn("该函数将被废弃", DeprecationWarning)
try:
warnings.simplefilter("error", DeprecationWarning)
deprecated_function()
except DeprecationWarning:
print("捕获到废弃警告")
捕获异常总结表格
异常类型 | 是否可以捕获 | 说明 | 示例 |
---|---|---|---|
BaseException | 否 | 所有异常的基类,通常不应直接捕获。 | - |
SystemExit | 否 | 表示程序正常退出,通常不应捕获。 | - |
KeyboardInterrupt | 否 | 用户按 Ctrl+C 终止程序,通常不应捕获。 | - |
GeneratorExit | 否 | 生成器关闭时抛出,不应捕获。 | - |
Exception | 是 | 大部分用户代码中的异常,常见的基类,可以捕获。 | try: ... except Exception: |
StopIteration | 否 | 迭代器结束时抛出,不应捕获。 | - |
StopAsyncIteration | 否 | 异步迭代器结束时抛出,不应捕获。 | - |
ArithmeticError | 是 | 算术运算错误的基类。 | 捕获 ZeroDivisionError , OverflowError , FloatingPointError |
ZeroDivisionError | 是 | 除数为零时抛出。 | try: 1 / 0 except ZeroDivisionError: |
OverflowError | 是 | 数值超出范围时抛出。 | try: math.exp(1000) except OverflowError: |
FloatingPointError | 是 | 浮点运算错误时抛出。 | - |
AssertionError | 是 | 断言失败时抛出。 | try: assert 1 == 2 except AssertionError: |
AttributeError | 是 | 尝试访问不存在的对象属性时抛出。 | try: obj.some_method() except AttributeError: |
BufferError | 是 | 缓冲区操作失败时抛出。 | - |
EOFError | 是 | 读取到文件末尾但无法返回数据时抛出。 | try: input() except EOFError: |
ImportError | 是 | 模块导入失败时抛出。 | try: import non_existent_module except ImportError: |
ModuleNotFoundError | 是 | 模块未找到时抛出。 | try: import non_existent_module except ModuleNotFoundError: |
LookupError | 是 | 查找操作失败的基类。 | 捕获 IndexError , KeyError |
IndexError | 是 | 序列访问越界时抛出。 | try: lst[100] except IndexError: |
KeyError | 是 | 字典查找不存在的键时抛出。 | try: dct["key"] except KeyError: |
MemoryError | 是 | 内存不足时抛出。 | - |
NameError | 是 | 访问未定义的变量时抛出。 | try: print(undefined_var) except NameError: |
UnboundLocalError | 是 | 使用未赋值的局部变量时抛出。 | - |
OSError | 是 | 系统级错误的基类,捕获文件和网络相关的错误。 | 捕获 FileNotFoundError , PermissionError , TimeoutError |
BlockingIOError | 是 | 非阻塞操作没有立即完成时抛出。 | - |
FileNotFoundError | 是 | 文件未找到时抛出。 | try: open("file.txt") except FileNotFoundError: |
PermissionError | 是 | 文件权限不足时抛出。 | try: open("file.txt", "w") except PermissionError: |
TimeoutError | 是 | 操作超时时抛出。 | - |
ReferenceError | 是 | 访问垃圾回收后的弱引用时抛出。 | - |
RuntimeError | 是 | 运行时错误的基类。 | try: raise RuntimeError("错误") except RuntimeError: |
NotImplementedError | 是 | 未实现的方法被调用时抛出。 | - |
RecursionError | 是 | 递归深度超出限制时抛出。 | try: def f(): f() except RecursionError: |
SyntaxError | 否 | 语法错误时抛出,编译时错误。 | - |
IndentationError | 否 | 缩进错误时抛出。 | - |
TabError | 否 | 混合使用 Tab 和空格时抛出。 | - |
SystemError | 否 | Python 解释器内部错误。 | - |
TypeError | 是 | 操作或函数应用于不适当类型时抛出。 | try: 1 + "a" except TypeError: |
ValueError | 是 | 函数接收到具有正确类型但不合理的参数时抛出。 | try: int("abc") except ValueError: |
UnicodeError | 是 | Unicode 编码相关错误的基类。 | 捕获 UnicodeDecodeError , UnicodeEncodeError , UnicodeTranslateError |
Warning | 是 | 可通过 warnings.catch_warnings() 捕获。 | try: warnings.warn("警告", UserWarning) except Warning: |
Python 中的异常处理
在 Python 中,异常处理通过 try
、except
、else
和 finally
四个关键字实现。这种机制让程序能够捕获并处理异常,避免程序崩溃,或在发生异常后执行一些清理操作。
1. try...except
基本结构
最基础的异常处理结构是 try...except
,用来捕获特定类型的异常。
try:
# 可能发生异常的代码
x = 1 / 0
except ZeroDivisionError: # 捕获指定异常类型
print("ZeroDivisionError: Division by zero!")
try
: 包含可能发生异常的代码。except
: 捕获并处理特定的异常。可以捕获多种类型的异常或所有异常。
2. 捕获多个异常
可以在一个 try
语句块中捕获多种异常。
try:
x = int("abc")
except (ValueError, TypeError): # 捕获多个异常
print("Caught ValueError or TypeError!")
3. 捕获所有异常
使用 except Exception
可以捕获所有继承自 Exception
的异常,但不推荐这样做,因为会忽略具体的错误类型。
try:
x = 1 / 0
except Exception as e: # 捕获所有 Exception 类型的异常
print(f"Caught an exception: {e}")
4. else
子句
else
子句在没有发生异常时执行,用于确保当 try
语句中的代码成功时执行某些操作。
try:
x = 1 / 1
except ZeroDivisionError:
print("Division by zero!")
else:
print("No exception, division successful!")
5. finally
子句
finally
子句无论是否发生异常都会执行,常用于清理资源,例如关闭文件或数据库连接。
try:
f = open("file.txt", "r")
except FileNotFoundError:
print("File not found!")
finally:
print("This block will always execute")
if 'f' in locals():
f.close()
6. 自定义异常处理
自定义异常处理结合 raise
语句可以手动抛出异常,也可以捕获并处理这些自定义异常。
class CustomError(Exception):
pass
try:
raise CustomError("Something went wrong")
except CustomError as e:
print(f"Caught custom exception: {e}")
7. 处理多个异常的结构
可以同时使用 try...except...else...finally
,让代码更具健壮性。
try:
num = int(input("Enter a number: "))
result = 10 / num
except ValueError:
print("ValueError: Please enter a valid number.")
except ZeroDivisionError:
print("ZeroDivisionError: Division by zero.")
else:
print(f"Division successful: {result}")
finally:
print("Cleaning up resources.")
常见场景总结
- 捕获特定异常: 根据具体的错误类型捕获和处理,以提供准确的错误信息。
- 清理资源: 在
finally
块中关闭文件、释放数据库连接等。 - 输入验证: 使用
try...except
处理用户输入错误。
异常处理的总结表格
异常处理关键字 | 描述 | 使用场景 |
---|---|---|
try | 包含可能抛出异常的代码 | 用于包围可能出错的代码段 |
except | 捕获并处理指定的异常 | 根据不同异常类型处理不同的错误 |
else | 当 try 块没有抛出异常时执行 | 只在没有异常时执行后续代码 |
finally | 无论是否发生异常,都会执行 | 清理资源,如关闭文件或网络连接 |
通过合理使用这些结构,Python 程序能够更健壮地应对错误,并保证在发生异常后进行清理工作。