Python 字节码是源代码经过编译后生成的中间代码,由 Python 解释器逐条执行,而 ExceptionTable 是字节码对象中专门用来记录异常处理范围的核心数据结构,它决定了当异常发生时解释器如何匹配对应的处理逻辑。

ExceptionTable 的基本概念
在 Python 3.11 及之后的版本中,异常处理的范围信息不再分散存储在字节码的各个位置,而是统一收敛到 ExceptionTable 中。它是一个数组结构,每个元素都对应一段字节码偏移范围,以及该范围内异常对应的处理入口偏移。
我们可以通过 dis 模块查看字节码对象的相关信息,其中就包含 ExceptionTable 的内容。比如下面这段简单的包含异常处理的代码:
def demo():
try:
a = 1 / 0
except ZeroDivisionError:
a = 0
return a
import dis
# 编译函数得到代码对象
code_obj = demo.__code__
# 打印代码对象的异常表
print(code_obj.co_exceptiontable)
ExceptionTable 的存储格式
ExceptionTable 的底层是字节串格式,每 8 个字节对应一个异常处理条目,每个条目的结构如下:
| 字节范围 | 含义 |
|---|---|
| 0-3 | 异常监控的起始字节码偏移(小端存储) |
| 4-5 | 异常监控的结束字节码偏移(小端存储,不包含该偏移) |
| 6-7 | 异常处理逻辑的入口字节码偏移(小端存储) |
我们可以通过代码解析这个字节串,得到具体的异常处理范围:
def parse_exception_table(exception_table):
entries = []
# 每8个字节一个条目
for i in range(0, len(exception_table), 8):
chunk = exception_table[i:i+8]
if len(chunk) < 8:
break
# 小端转整数
start = int.from_bytes(chunk[0:4], byteorder='little')
end = int.from_bytes(chunk[4:6], byteorder='little')
handler = int.from_bytes(chunk[6:8], byteorder='little')
entries.append((start, end, handler))
return entries
code_obj = demo.__code__
entries = parse_exception_table(code_obj.co_exceptiontable)
for idx, (start, end, handler) in enumerate(entries):
print(f"条目{idx}: 监控范围[{start}, {end}), 处理入口偏移: {handler}")
ExceptionTable 在异常处理中的作用
当 Python 解释器执行字节码过程中抛出异常时,会按照以下步骤匹配处理逻辑:
- 首先获取当前执行的字节码偏移位置
- 遍历 ExceptionTable 中的所有条目,找到包含当前偏移的监控范围
- 如果找到对应条目,就跳转到条目的处理入口偏移位置执行异常处理逻辑
- 如果没有找到匹配的条目,就将异常向上层调用栈传递
我们可以通过反汇编字节码来验证这个流程,使用 dis.dis 查看 demo 函数的字节码:
dis.dis(demo)
反汇编结果中会显示每个字节码的偏移,以及对应的 ExceptionTable 条目,我们可以对应起来看到 try 块对应的字节码范围,以及 except 块对应的处理入口偏移。
不同版本的差异说明
在 Python 3.11 之前,异常处理的范围信息是通过字节码中的 SETUP_EXCEPT 等指令来标记的,这些指令会直接嵌入到字节码流中,而 3.11 及之后版本将这部分信息统一放到了 ExceptionTable 中,减少了字节码流的长度,也提升了异常处理的匹配效率。
如果我们需要兼容不同版本的字节码分析逻辑,需要先判断 Python 版本,再选择对应的异常处理信息解析方式:
import sys
def get_exception_info(code_obj):
if sys.version_info >= (3, 11):
# 3.11+ 使用 ExceptionTable
return parse_exception_table(code_obj.co_exceptiontable)
else:
# 旧版本需要从字节码指令中提取异常处理范围
# 这里省略旧版本的解析逻辑
return []
实际应用场景
理解 ExceptionTable 的主要应用场景包括:
- 字节码级别的程序调试,定位异常处理不生效的原因
- 编写字节码修改、优化工具时,正确维护异常处理的范围信息
- 分析 Python 解释器的异常处理底层实现逻辑
如果我们在修改字节码时遗漏了 ExceptionTable 的更新,就可能导致异常处理逻辑失效,甚至引发解释器崩溃,因此操作字节码时一定要注意同步维护这个结构。
Python字节码ExceptionTable异常处理修改时间:2026-07-16 13:42:29