dis
— Python 字节码反汇编器¶
源代码: Lib/dis.py
The dis
模块支持通过反汇编来分析 CPython 字节码。此模块作为输入的 CPython 字节码在文件 Include/opcode.h
中定义,并由编译器和解释器使用。
CPython 实现细节: 字节码是 CPython 解释器的实现细节。不保证字节码在不同版本的 Python 之间不会被添加、删除或更改。不应认为此模块在不同 Python VM 或 Python 版本之间工作。
在版本 3.6 中更改: 每个指令使用 2 个字节。以前字节数因指令而异。
在版本 3.10 中更改: 跳转、异常处理和循环指令的参数现在是指令偏移量,而不是字节偏移量。
示例: 给定函数 myfunc()
def myfunc(alist):
return len(alist)
可以使用以下命令显示 myfunc()
的反汇编结果
>>> dis.dis(myfunc)
2 0 RESUME 0
3 2 LOAD_GLOBAL 1 (NULL + len)
12 LOAD_FAST 0 (alist)
14 CALL 1
22 RETURN_VALUE
(“2” 是行号)。
命令行界面¶
The dis
模块可以作为脚本从命令行调用
python -m dis [-h] [infile]
接受以下选项
- -h, --help¶
显示用法并退出。
如果指定了 infile
,则其反汇编代码将写入 stdout。否则,将对从 stdin 收到的已编译源代码执行反汇编。
字节码分析¶
在版本 3.4 中添加。
字节码分析 API 允许将 Python 代码片段包装在 Bytecode
对象中,该对象提供对已编译代码的详细信息的轻松访问。
- class dis.Bytecode(x, *, first_line=None, current_offset=None, show_caches=False, adaptive=False)¶
分析与函数、生成器、异步生成器、协程、方法、源代码字符串或代码对象(由
compile()
返回)相对应的字节码。这是对下面列出的许多函数(最值得注意的是
get_instructions()
)的便捷包装器,因为迭代Bytecode
实例会产生字节码操作作为Instruction
实例。如果 first_line 不是
None
,则它表示应为反汇编代码中的第一行源代码报告的行号。否则,源代码行信息(如果有)将直接从反汇编的代码对象中获取。如果 current_offset 不是
None
,则它指的是反汇编代码中的指令偏移量。设置此值意味着dis()
将在指定的 opcode 处显示“当前指令”标记。如果 show_caches 为
True
,则dis()
将显示解释器用来专门化字节码的内联缓存条目。如果 adaptive 为
True
,则dis()
将显示专门化的字节码,它可能与原始字节码不同。- classmethod from_traceback(tb, *, show_caches=False)¶
从给定的跟踪信息构建
Bytecode
实例,将 current_offset 设置为导致异常的指令。
- codeobj¶
已编译的代码对象。
- first_line¶
代码对象的第一个源代码行(如果可用)。
- info()¶
返回一个格式化的多行字符串,其中包含有关代码对象的详细信息,例如
code_info()
。
在版本 3.7 中更改: 现在可以处理协程和异步生成器对象。
在版本 3.11 中更改: 添加了 show_caches 和 adaptive 参数。
示例
>>> bytecode = dis.Bytecode(myfunc)
>>> for instr in bytecode:
... print(instr.opname)
...
RESUME
LOAD_GLOBAL
LOAD_FAST
CALL
RETURN_VALUE
分析函数¶
The dis
模块还定义了以下分析函数,这些函数将输入直接转换为所需的输出。如果只执行单个操作,它们可能很有用,因此中间分析对象没有用。
- dis.code_info(x)¶
返回一个格式化的多行字符串,其中包含为提供的函数、生成器、异步生成器、协程、方法、源代码字符串或代码对象提供的详细代码对象信息。
请注意,代码信息字符串的确切内容高度依赖于实现,并且它们可能在不同的 Python VM 或 Python 版本之间任意更改。
在版本 3.2 中添加。
在版本 3.7 中更改: 现在可以处理协程和异步生成器对象。
- dis.show_code(x, *, file=None)¶
将提供的函数、方法、源代码字符串或代码对象的详细代码对象信息打印到 file(如果未指定 file,则打印到
sys.stdout
)。这是
print(code_info(x), file=file)
的便捷简写,旨在用于解释器提示符处的交互式探索。在版本 3.2 中添加。
在版本 3.4 中更改:添加了 file 参数。
- dis.dis(x=None, *, file=None, depth=None, show_caches=False, adaptive=False)¶
反汇编 x 对象。x 可以表示模块、类、方法、函数、生成器、异步生成器、协程、代码对象、源代码字符串或原始字节码的字节序列。对于模块,它反汇编所有函数。对于类,它反汇编所有方法(包括类方法和静态方法)。对于代码对象或原始字节码序列,它为每个字节码指令打印一行。它还递归地反汇编嵌套的代码对象。这些可以包括生成器表达式、嵌套函数、嵌套类的主体以及用于 注释范围 的代码对象。字符串首先使用
compile()
内置函数编译为代码对象,然后再反汇编。如果没有提供对象,此函数将反汇编最后一个回溯。反汇编结果将以文本形式写入提供的 file 参数,如果没有提供,则写入
sys.stdout
。除非 depth 为
None
,否则递归的最大深度受 depth 限制。depth=0
表示不递归。如果 show_caches 为
True
,此函数将显示解释器用于专门化字节码的内联缓存条目。如果 adaptive 为
True
,此函数将显示可能与原始字节码不同的专门化字节码。在版本 3.4 中更改:添加了 file 参数。
在版本 3.7 中更改:实现了递归反汇编并添加了 depth 参数。
在版本 3.7 中更改: 现在可以处理协程和异步生成器对象。
在版本 3.11 中更改: 添加了 show_caches 和 adaptive 参数。
- dis.distb(tb=None, *, file=None, show_caches=False, adaptive=False)¶
反汇编回溯的栈顶函数,如果未传递任何回溯,则使用最后一个回溯。导致异常的指令将被指示。
反汇编结果将以文本形式写入提供的 file 参数,如果没有提供,则写入
sys.stdout
。在版本 3.4 中更改:添加了 file 参数。
在版本 3.11 中更改: 添加了 show_caches 和 adaptive 参数。
- dis.disassemble(code, lasti=-1, *, file=None, show_caches=False, adaptive=False)¶
- dis.disco(code, lasti=-1, *, file=None, show_caches=False, adaptive=False)¶
反汇编代码对象,如果提供了 lasti,则指示最后一条指令。输出分为以下几列
每行的第一条指令的行号
当前指令,用
-->
表示带标签的指令,用
>>
表示指令的地址
操作码名称
操作参数
参数的解释(在括号中)。
参数解释识别局部变量和全局变量名称、常量值、分支目标和比较运算符。
反汇编结果将以文本形式写入提供的 file 参数,如果没有提供,则写入
sys.stdout
。在版本 3.4 中更改:添加了 file 参数。
在版本 3.11 中更改: 添加了 show_caches 和 adaptive 参数。
- dis.get_instructions(x, *, first_line=None, show_caches=False, adaptive=False)¶
返回提供的函数、方法、源代码字符串或代码对象中的指令的迭代器。
迭代器生成一系列
Instruction
命名元组,提供提供的代码中每个操作的详细信息。如果 first_line 不是
None
,则它表示应为反汇编代码中的第一行源代码报告的行号。否则,源代码行信息(如果有)将直接从反汇编的代码对象中获取。show_caches 和 adaptive 参数的工作方式与
dis()
中的相同。在版本 3.4 中添加。
在版本 3.11 中更改: 添加了 show_caches 和 adaptive 参数。
- dis.findlinestarts(code)¶
此生成器函数使用
co_lines()
方法,该方法属于 代码对象 code,用于查找源代码中行的起始偏移量。它们以(offset, lineno)
对的形式生成。在 3.6 版本中变更: 行号可以递减。之前,它们总是递增的。
在 3.10 版本中变更: 使用 PEP 626
co_lines()
方法,而不是co_firstlineno
和co_lnotab
属性,它们属于 代码对象。
- dis.findlabels(code)¶
检测原始编译字节码字符串 code 中所有作为跳转目标的偏移量,并返回这些偏移量的列表。
- dis.stack_effect(opcode, oparg=None, *, jump=None)¶
计算 opcode 带参数 oparg 的堆栈效应。
如果代码有跳转目标并且 jump 为
True
,stack_effect()
将返回跳转的堆栈效应。如果 jump 为False
,它将返回不跳转的堆栈效应。如果 jump 为None
(默认值),它将返回两种情况的最大堆栈效应。在版本 3.4 中添加。
在 3.8 版本中变更: 添加了 jump 参数。
Python 字节码指令¶
get_instructions()
函数和 Bytecode
类以 Instruction
实例的形式提供字节码指令的详细信息。
- class dis.Instruction¶
字节码操作的详细信息
- opname¶
操作的人类可读名称
- arg¶
操作的数字参数(如果有),否则为
None
- argval¶
解析后的参数值(如果有),否则为
None
- argrepr¶
操作参数的人类可读描述(如果有),否则为空字符串。
- offset¶
操作在字节码序列中的起始索引
- starts_line¶
此操作码开始的行(如果有),否则为
None
- is_jump_target¶
True
如果其他代码跳转到这里,否则为False
- positions¶
dis.Positions
对象,保存此指令覆盖的开始和结束位置。
在版本 3.4 中添加。
在 3.11 版本中变更: 添加了字段
positions
。
- class dis.Positions¶
如果信息不可用,某些字段可能为
None
。- lineno¶
- end_lineno¶
- col_offset¶
- end_col_offset¶
在 3.11 版本中添加。
Python 编译器目前生成以下字节码指令。
通用指令
在下文中,我们将解释器堆栈称为 STACK
,并将描述对它的操作,就好像它是一个 Python 列表一样。堆栈顶端对应于此语言中的 STACK[-1]
。
- NOP¶
不执行任何操作的代码。用作字节码优化器的占位符,以及生成行跟踪事件。
- POP_TOP¶
删除堆栈顶部的项目
STACK.pop()
- END_FOR¶
从堆栈中删除前两个值。等效于
POP_TOP
;POP_TOP
。用于在循环结束时清理,因此得名。在 3.12 版本中添加。
- END_SEND¶
实现
del STACK[-2]
。用于在生成器退出时清理。在 3.12 版本中添加。
- COPY(i)¶
将第 i 个项目推送到堆栈顶部,而不将其从原始位置删除
assert i > 0 STACK.append(STACK[-i])
在 3.11 版本中添加。
- SWAP(i)¶
将堆栈顶部与第 i 个元素交换
STACK[-i], STACK[-1] = STACK[-1], STACK[-i]
在 3.11 版本中添加。
- CACHE¶
此操作码并非实际指令,而是用于为解释器标记额外的空间,以便解释器直接在字节码中缓存有用的数据。它被所有
dis
工具自动隐藏,但可以使用show_caches=True
查看。从逻辑上讲,此空间是前一个指令的一部分。许多操作码期望后面跟着确切数量的缓存,并将指示解释器在运行时跳过它们。
填充的缓存可能看起来像任意指令,因此在读取或修改包含加速数据的原始自适应字节码时,应格外小心。
在 3.11 版本中添加。
一元运算
一元运算从堆栈顶部获取值,应用运算,并将结果压回堆栈。
- UNARY_NEGATIVE¶
实现
STACK[-1] = -STACK[-1]
。
- UNARY_NOT¶
实现
STACK[-1] = not STACK[-1]
。
- UNARY_INVERT¶
实现
STACK[-1] = ~STACK[-1]
。
- GET_ITER¶
实现
STACK[-1] = iter(STACK[-1])
。
- GET_YIELD_FROM_ITER¶
如果
STACK[-1]
是一个 生成器迭代器 或 协程 对象,则保持不变。否则,实现STACK[-1] = iter(STACK[-1])
。在版本 3.5 中添加。
二元运算和就地运算
二元运算从堆栈中移除最上面的两个元素 (STACK[-1]
和 STACK[-2]
)。它们执行运算,然后将结果放回堆栈。
就地运算类似于二元运算,但当 STACK[-2]
支持时,运算是在原地完成的,并且生成的 STACK[-1]
可能是(但不必是)原始的 STACK[-2]
。
- BINARY_OP(op)¶
实现二元运算和就地运算(取决于 op 的值)。
rhs = STACK.pop() lhs = STACK.pop() STACK.append(lhs op rhs)
在 3.11 版本中添加。
- BINARY_SUBSCR¶
实现
key = STACK.pop() container = STACK.pop() STACK.append(container[key])
- STORE_SUBSCR¶
实现
key = STACK.pop() container = STACK.pop() value = STACK.pop() container[key] = value
- DELETE_SUBSCR¶
实现
key = STACK.pop() container = STACK.pop() del container[key]
- BINARY_SLICE¶
实现
end = STACK.pop() start = STACK.pop() container = STACK.pop() STACK.append(container[start:end])
在 3.12 版本中添加。
- STORE_SLICE¶
实现
end = STACK.pop() start = STACK.pop() container = STACK.pop() values = STACK.pop() container[start:end] = value
在 3.12 版本中添加。
协程操作码
- GET_AWAITABLE(where)¶
实现
STACK[-1] = get_awaitable(STACK[-1])
,其中get_awaitable(o)
返回o
如果o
是一个协程对象或带有CO_ITERABLE_COROUTINE
标志的生成器对象,或者解析o.__await__
。如果
where
操作数不为零,则表示指令出现的位置1
:在调用__aenter__
之后2
:在调用__aexit__
之后
在版本 3.5 中添加。
在版本 3.11 中更改: 以前,此指令没有 oparg。
- GET_AITER¶
实现
STACK[-1] = STACK[-1].__aiter__()
。在版本 3.5 中添加。
在版本 3.7 中更改: 不再支持从
__aiter__
返回可等待对象。
- GET_ANEXT¶
在堆栈中实现
STACK.append(get_awaitable(STACK[-1].__anext__()))
。有关get_awaitable
的详细信息,请参阅GET_AWAITABLE
。在版本 3.5 中添加。
- END_ASYNC_FOR¶
终止
async for
循环。处理在等待下一个项目时引发的异常。堆栈在STACK[-2]
中包含异步可迭代对象,在STACK[-1]
中包含引发的异常。两者都被弹出。如果异常不是StopAsyncIteration
,则重新引发。在版本 3.8 中添加。
在版本 3.11 中更改: 堆栈上的异常表示现在包含一个项目,而不是三个项目。
- CLEANUP_THROW¶
处理在当前帧中通过
throw()
或close()
调用期间引发的异常。如果STACK[-1]
是StopIteration
的实例,则从堆栈中弹出三个值并压入其value
成员。否则,重新引发STACK[-1]
。在 3.12 版本中添加。
- BEFORE_ASYNC_WITH¶
从
STACK[-1]
中解析__aenter__
和__aexit__
。将__aexit__
和__aenter__()
的结果压入堆栈。STACK.extend((__aexit__, __aenter__())
在版本 3.5 中添加。
其他操作码
- SET_ADD(i)¶
实现
item = STACK.pop() set.add(STACK[-i], item)
用于实现集合推导。
- LIST_APPEND(i)¶
实现
item = STACK.pop() list.append(STACK[-i], item)
用于实现列表推导。
- MAP_ADD(i)¶
实现
value = STACK.pop() key = STACK.pop() dict.__setitem__(STACK[-i], key, value)
用于实现字典推导。
在版本 3.1 中添加。
在版本 3.8 中更改: 映射值是
STACK[-1]
,映射键是STACK[-2]
。之前,它们是反转的。
对于所有 SET_ADD
、LIST_APPEND
和 MAP_ADD
指令,虽然添加的值或键值对被弹出,但容器对象仍然保留在堆栈中,以便它可用于循环的进一步迭代。
- RETURN_VALUE¶
使用
STACK[-1]
返回给函数的调用者。
- RETURN_CONST(consti)¶
返回
co_consts[consti]
给函数的调用者。在 3.12 版本中添加。
- YIELD_VALUE¶
从一个 生成器 中生成
STACK.pop()
。在 3.11 版本中变更: oparg 设置为堆栈深度。
在 3.12 版本中变更: oparg 设置为异常块深度,用于高效地关闭生成器。
- SETUP_ANNOTATIONS¶
检查
__annotations__
是否在locals()
中定义,如果未定义,则将其设置为一个空的dict
。此操作码仅在类或模块主体包含 变量注释 时静态地发出。在 3.6 版本中添加。
- POP_EXCEPT¶
从堆栈中弹出值,用于恢复异常状态。
在版本 3.11 中更改: 堆栈上的异常表示现在包含一个项目,而不是三个项目。
- RERAISE¶
重新抛出当前堆栈顶部的异常。如果 oparg 非零,则从堆栈中弹出另一个值,用于设置当前帧的
f_lasti
。在 3.9 版本中添加。
在版本 3.11 中更改: 堆栈上的异常表示现在包含一个项目,而不是三个项目。
- PUSH_EXC_INFO¶
从堆栈中弹出值。将当前异常推送到堆栈顶部。将最初弹出的值推回堆栈。在异常处理程序中使用。
在 3.11 版本中添加。
- CHECK_EXC_MATCH¶
执行
except
的异常匹配。测试STACK[-2]
是否是与STACK[-1]
匹配的异常。弹出STACK[-1]
并将测试的布尔结果推送到堆栈。在 3.11 版本中添加。
- CHECK_EG_MATCH¶
执行
except*
的异常匹配。对表示STACK[-2]
的异常组应用split(STACK[-1])
。如果匹配,则从堆栈中弹出两个项目并推入不匹配的子组(如果完全匹配则为
None
),然后推入匹配的子组。如果未匹配,则弹出单个项目(匹配类型)并推入None
。在 3.11 版本中添加。
- WITH_EXCEPT_START¶
使用参数 (type, val, tb) 调用堆栈中位置 4 的函数,这些参数表示堆栈顶部的异常。用于在
with
语句中发生异常时实现调用context_manager.__exit__(*exc_info())
。在 3.9 版本中添加。
在 3.11 版本中变更:
__exit__
函数位于堆栈的第 4 个位置,而不是第 7 个位置。堆栈上的异常表示现在包含一个项目,而不是三个项目。
- LOAD_ASSERTION_ERROR¶
将
AssertionError
推送到堆栈。由assert
语句使用。在 3.9 版本中添加。
- LOAD_BUILD_CLASS¶
将
builtins.__build_class__()
推送到堆栈。稍后调用它来构造一个类。
- BEFORE_WITH¶
此操作码在 with 块开始之前执行几个操作。首先,它从上下文管理器中加载
__exit__()
并将其推送到堆栈,以便稍后由WITH_EXCEPT_START
使用。然后,调用__enter__()
。最后,将调用__enter__()
方法的结果推送到堆栈。在 3.11 版本中添加。
- GET_LEN¶
执行
STACK.append(len(STACK[-1]))
。在 3.10 版本中添加。
- MATCH_MAPPING¶
如果
STACK[-1]
是collections.abc.Mapping
的实例(或者更准确地说:如果它在Py_TPFLAGS_MAPPING
标志在其tp_flags
中设置),则将True
推送到堆栈。否则,将False
推送到堆栈。在 3.10 版本中添加。
- MATCH_SEQUENCE¶
如果
STACK[-1]
是collections.abc.Sequence
的实例,并且不是str
/bytes
/bytearray
的实例(或者更准确地说:如果它在Py_TPFLAGS_SEQUENCE
标志在其tp_flags
中设置),则将True
推送到堆栈。否则,将False
推送到堆栈。在 3.10 版本中添加。
- MATCH_KEYS¶
STACK[-1]
是映射键的元组,而STACK[-2]
是匹配主体。如果STACK[-2]
包含STACK[-1]
中的所有键,则推入一个包含相应值的tuple
。否则,推入None
。在 3.10 版本中添加。
在 3.11 版本中变更: 以前,此指令还推入一个布尔值,表示成功(
True
)或失败(False
)。
- STORE_NAME(namei)¶
实现
name = STACK.pop()
。namei 是 name 在co_names
属性中的索引,该属性属于 代码对象。编译器尝试使用STORE_FAST
或STORE_GLOBAL
(如果可能)。
- UNPACK_SEQUENCE(count)¶
将
STACK[-1]
解包为 count 个单独的值,这些值按从右到左的顺序放到堆栈中。要求正好有 count 个值。assert(len(STACK[-1]) == count) STACK.extend(STACK.pop()[:-count-1:-1])
- UNPACK_EX(counts)¶
实现带星号目标的赋值:将
STACK[-1]
中的可迭代对象解包为单独的值,其中值的总数可能小于可迭代对象中的项目数:新值之一将是所有剩余项目的列表。列表值之前和之后的数值限制为 255。
列表值之前的数值数量在操作码的参数中编码。列表之后的值的数量(如果有)使用
EXTENDED_ARG
编码。因此,参数可以被视为一个两个字节的值,其中counts 的低字节是列表值之前的数值数量,counts 的高字节是列表值之后的值数量。提取的值以从右到左的顺序放入堆栈中,即
a, *b, c = d
在执行后将被存储为STACK.extend((a, b, c))
。
- STORE_ATTR(namei)¶
实现
obj = STACK.pop() value = STACK.pop() obj.name = value
- STORE_GLOBAL(namei)¶
与
STORE_NAME
相同,但将名称存储为全局变量。
- DELETE_GLOBAL(namei)¶
与
DELETE_NAME
相同,但删除全局名称。
- LOAD_CONST(consti)¶
将
co_consts[consti]
推入堆栈。
- LOAD_NAME(namei)¶
将与
co_names[namei]
关联的值推入堆栈。名称在局部变量中查找,然后在全局变量中查找,最后在内置函数中查找。
- LOAD_LOCALS¶
将对局部变量字典的引用推入堆栈。这用于为
LOAD_FROM_DICT_OR_DEREF
和LOAD_FROM_DICT_OR_GLOBALS
准备命名空间字典。在 3.12 版本中添加。
- LOAD_FROM_DICT_OR_GLOBALS(i)¶
从堆栈中弹出映射,并查找
co_names[namei]
的值。如果名称在映射中找不到,则在全局变量和内置函数中查找,类似于LOAD_GLOBAL
。这用于在类体内的 注释作用域 中加载全局变量。在 3.12 版本中添加。
- BUILD_TUPLE(count)¶
从堆栈中消耗count 个项目创建一个元组,并将生成的元组推入堆栈。
assert count > 0 STACK, values = STACK[:-count], STACK[-count:] STACK.append(tuple(values))
- BUILD_LIST(count)¶
与
BUILD_TUPLE
相同,但创建列表。
- BUILD_SET(count)¶
与
BUILD_TUPLE
相同,但创建集合。
- BUILD_MAP(count)¶
将一个新的字典对象推入堆栈。弹出
2 * count
个项目,以便字典包含count 个条目:{..., STACK[-4]: STACK[-3], STACK[-2]: STACK[-1]}
。在版本 3.5 中更改: 字典是从堆栈项目创建的,而不是创建一个预先分配了count 个条目的空字典。
- BUILD_CONST_KEY_MAP(count)¶
专门用于常量键的
BUILD_MAP
版本。弹出堆栈顶部的元素,该元素包含一个键元组,然后从STACK[-2]
开始,弹出count 个值以形成构建字典中的值。在 3.6 版本中添加。
- BUILD_STRING(count)¶
将堆栈中的count 个字符串连接起来,并将生成的字符串推入堆栈。
在 3.6 版本中添加。
- LIST_EXTEND(i)¶
实现
seq = STACK.pop() list.extend(STACK[-i], seq)
用于构建列表。
在 3.9 版本中添加。
- SET_UPDATE(i)¶
实现
seq = STACK.pop() set.update(STACK[-i], seq)
用于构建集合。
在 3.9 版本中添加。
- DICT_UPDATE(i)¶
实现
map = STACK.pop() dict.update(STACK[-i], map)
用于构建字典。
在 3.9 版本中添加。
- DICT_MERGE(i)¶
与
DICT_UPDATE
相同,但对于重复键会引发异常。在 3.9 版本中添加。
- LOAD_ATTR(namei)¶
如果
namei
的低位没有设置,则用getattr(STACK[-1], co_names[namei>>1])
替换STACK[-1]
。如果
namei
的最低位被设置,则尝试从STACK[-1]
对象中加载名为co_names[namei>>1]
的方法。STACK[-1]
被弹出。此字节码区分两种情况:如果STACK[-1]
具有与正确名称匹配的方法,则字节码将推入未绑定方法和STACK[-1]
。STACK[-1]
将在调用未绑定方法时被用作第一个参数 (self
)CALL
。否则,将推入NULL
和属性查找返回的对象。在版本 3.12 中更改: 如果
namei
的最低位被设置,则在属性或未绑定方法之前分别将NULL
或self
推入堆栈。
- LOAD_SUPER_ATTR(namei)¶
此操作码实现
super()
,包括其零参数和双参数形式(例如super().method()
、super().attr
和super(cls, self).method()
、super(cls, self).attr
)。它从堆栈中弹出三个值(从堆栈顶部向下): -
self
:当前方法的第一个参数 -cls
:定义当前方法的类 - 全局super
关于其参数,它的工作方式类似于
LOAD_ATTR
,除了namei
向左移位 2 位而不是 1 位。namei
的最低位表示尝试加载方法,与LOAD_ATTR
一样,这会导致推入NULL
和加载的方法。当它未设置时,将单个值推入堆栈。namei
的第二低位,如果设置,表示这是一个对super()
的双参数调用(未设置表示零参数)。在 3.12 版本中添加。
- COMPARE_OP(opname)¶
执行布尔运算。运算名称可以在
cmp_op[opname]
中找到。
- IS_OP(invert)¶
执行
is
比较,如果invert
为 1,则执行is not
。在 3.9 版本中添加。
- CONTAINS_OP(invert)¶
执行
in
比较,如果invert
为 1,则执行not in
。在 3.9 版本中添加。
- IMPORT_NAME(namei)¶
导入模块
co_names[namei]
。STACK[-1]
和STACK[-2]
被弹出,并提供__import__()
的 fromlist 和 level 参数。模块对象被推入堆栈。当前命名空间不受影响:对于正确的导入语句,后续的STORE_FAST
指令将修改命名空间。
- IMPORT_FROM(namei)¶
从
STACK[-1]
中找到的模块中加载属性co_names[namei]
。结果对象被推入堆栈,以便随后由STORE_FAST
指令存储。
- JUMP_FORWARD(delta)¶
将字节码计数器增加 delta。
- JUMP_BACKWARD(delta)¶
将字节码计数器减少 delta。检查中断。
在 3.11 版本中添加。
- JUMP_BACKWARD_NO_INTERRUPT(delta)¶
将字节码计数器减少 delta。不检查中断。
在 3.11 版本中添加。
- POP_JUMP_IF_TRUE(delta)¶
如果
STACK[-1]
为真,则将字节码计数器增加 delta。STACK[-1]
被弹出。在版本 3.11 中更改: oparg 现在是相对增量,而不是绝对目标。此操作码是一个伪指令,在最终字节码中被定向版本(向前/向后)替换。
在版本 3.12 中更改: 这不再是伪指令。
- POP_JUMP_IF_FALSE(delta)¶
如果
STACK[-1]
为假,则将字节码计数器增加 delta。STACK[-1]
被弹出。在版本 3.11 中更改: oparg 现在是相对增量,而不是绝对目标。此操作码是一个伪指令,在最终字节码中被定向版本(向前/向后)替换。
在版本 3.12 中更改: 这不再是伪指令。
- POP_JUMP_IF_NOT_NONE(delta)¶
如果
STACK[-1]
不为None
,则将字节码计数器增加 delta。STACK[-1]
被弹出。此操作码是一个伪指令,在最终字节码中被定向版本(向前/向后)替换。
在 3.11 版本中添加。
在版本 3.12 中更改: 这不再是伪指令。
- POP_JUMP_IF_NONE(delta)¶
如果
STACK[-1]
为None
,则将字节码计数器增加 delta。STACK[-1]
被弹出。此操作码是一个伪指令,在最终字节码中被定向版本(向前/向后)替换。
在 3.11 版本中添加。
在版本 3.12 中更改: 这不再是伪指令。
- FOR_ITER(delta)¶
STACK[-1]
是一个 迭代器。调用其__next__()
方法。如果这产生了一个新值,则将其推入堆栈(在它下面留下迭代器)。如果迭代器指示它已耗尽,则字节码计数器将增加 delta。在版本 3.12 中更改: 在 3.11 之前,迭代器在耗尽时被弹出。
- LOAD_GLOBAL(namei)¶
将名为
co_names[namei>>1]
的全局变量加载到堆栈中。在版本 3.11 中更改: 如果
namei
的最低位被设置,则在全局变量之前将NULL
推入堆栈。
- LOAD_FAST(var_num)¶
将对局部变量
co_varnames[var_num]
的引用推入堆栈。在版本 3.12 中更改: 此操作码现在仅在局部变量保证已初始化的情况下使用。它不会引发
UnboundLocalError
。
- LOAD_FAST_CHECK(var_num)¶
将本地变量
co_varnames[var_num]
的引用压入堆栈,如果本地变量尚未初始化,则引发UnboundLocalError
。在 3.12 版本中添加。
- LOAD_FAST_AND_CLEAR(var_num)¶
将本地变量
co_varnames[var_num]
的引用压入堆栈(如果本地变量尚未初始化,则将NULL
压入堆栈),并将co_varnames[var_num]
设置为NULL
。在 3.12 版本中添加。
- STORE_FAST(var_num)¶
将
STACK.pop()
存储到本地变量co_varnames[var_num]
中。
- DELETE_FAST(var_num)¶
删除本地变量
co_varnames[var_num]
。
- MAKE_CELL(i)¶
在插槽
i
中创建一个新的单元格。如果该插槽不为空,则将该值存储到新的单元格中。在 3.11 版本中添加。
- LOAD_CLOSURE(i)¶
将“快速局部变量”存储区中插槽
i
中包含的单元格的引用压入堆栈。变量的名称是co_fastlocalnames[i]
。请注意,
LOAD_CLOSURE
实际上是LOAD_FAST
的别名。它存在是为了使字节码更易读。在版本 3.11 中更改:
i
不再以co_varnames
的长度为偏移量。
- LOAD_DEREF(i)¶
加载“快速局部变量”存储区中插槽
i
中包含的单元格。将单元格包含的对象的引用压入堆栈。在版本 3.11 中更改:
i
不再以co_varnames
的长度为偏移量。
- LOAD_FROM_DICT_OR_DEREF(i)¶
从堆栈中弹出映射,并在该映射中查找与“快速局部变量”存储区中插槽
i
关联的名称。如果在映射中找不到该名称,则从插槽i
中包含的单元格中加载它,类似于LOAD_DEREF
。这用于在类体(以前使用LOAD_CLASSDEREF
)和类体内的 注释范围 中加载自由变量。在 3.12 版本中添加。
- STORE_DEREF(i)¶
将
STACK.pop()
存储到“快速局部变量”存储区中插槽i
中包含的单元格中。在版本 3.11 中更改:
i
不再以co_varnames
的长度为偏移量。
- DELETE_DEREF(i)¶
清空“快速局部变量”存储区中插槽
i
中包含的单元格。由del
语句使用。在版本 3.2 中添加。
在版本 3.11 中更改:
i
不再以co_varnames
的长度为偏移量。
- COPY_FREE_VARS(n)¶
将闭包中的
n
个自由变量复制到框架中。在调用闭包时,消除了对调用方代码进行特殊处理的需要。在 3.11 版本中添加。
- RAISE_VARARGS(argc)¶
根据 argc 的值,使用
raise
语句的 3 种形式之一引发异常0:
raise
(重新引发之前的异常)1:
raise STACK[-1]
(引发STACK[-1]
处的异常实例或类型)2:
raise STACK[-2] from STACK[-1]
(引发STACK[-2]
处的异常实例或类型,并将__cause__
设置为STACK[-1]
)
- CALL(argc)¶
使用
argc
指定的参数数量调用可调用对象,包括由前面的KW_NAMES
指定的命名参数(如果有)。堆栈中(按升序)包含以下内容之一:NULL
可调用对象
位置参数
命名参数
或
可调用对象
self
剩余的位置参数
命名参数
argc
是位置参数和命名参数的总数,不包括当NULL
不存在时self
。CALL
从堆栈中弹出所有参数和可调用对象,使用这些参数调用可调用对象,并将可调用对象返回的返回值压入堆栈。在 3.11 版本中添加。
- CALL_FUNCTION_EX(flags)¶
使用一组可变的位置参数和关键字参数调用可调用对象。如果 flags 的最低位被设置,则堆栈的顶部包含一个映射对象,其中包含额外的关键字参数。在调用可调用对象之前,映射对象和可迭代对象分别被“解包”,并将它们的内容作为关键字参数和位置参数传递。
CALL_FUNCTION_EX
从堆栈中弹出所有参数和可调用对象,使用这些参数调用可调用对象,并将可调用对象返回的返回值压入堆栈。在 3.6 版本中添加。
- PUSH_NULL¶
将
NULL
压入堆栈。在调用序列中使用,以匹配LOAD_METHOD
为非方法调用压入的NULL
。在 3.11 版本中添加。
- KW_NAMES(consti)¶
为
CALL
添加前缀。将对co_consts[consti]
的引用存储到内部变量中,供CALL
使用。co_consts[consti]
必须是一个字符串元组。在 3.11 版本中添加。
- MAKE_FUNCTION(flags)¶
在堆栈上压入一个新的函数对象。从下到上,消耗的堆栈必须包含值,如果参数带有指定的标志值
0x01
位置参数和位置或关键字参数的默认值元组,按位置顺序排列0x02
关键字参数默认值的字典0x04
包含参数注释的字符串元组0x08
包含自由变量单元的元组,用于创建闭包与函数关联的代码(位于
STACK[-1]
)
在 3.10 版本中变更: 标志值
0x04
是字符串元组而不是字典在 3.11 版本中变更:
STACK[-1]
中的限定名称已删除。
- BUILD_SLICE(argc)¶
在堆栈上压入一个切片对象。argc 必须是 2 或 3。如果它是 2,则实现
end = STACK.pop() start = STACK.pop() STACK.append(slice(start, stop))
如果它是 3,则实现
step = STACK.pop() end = STACK.pop() start = STACK.pop() STACK.append(slice(start, end, step))
有关更多信息,请参阅
slice()
内置函数。
- EXTENDED_ARG(ext)¶
为任何参数过大而无法放入默认一个字节的指令添加前缀。ext 持有一个额外的字节,充当参数的高位。对于每个指令,最多允许三个前缀
EXTENDED_ARG
,形成一个从两个字节到四个字节的参数。
- FORMAT_VALUE(flags)¶
用于实现格式化字面量字符串(f-字符串)。从堆栈中弹出可选的 fmt_spec,然后弹出必需的 value。flags 的解释如下
(flags & 0x03) == 0x00
: value 按原样格式化。(flags & 0x03) == 0x01
: 在格式化之前,对 value 调用str()
。(flags & 0x03) == 0x02
: 在格式化之前,对 value 调用repr()
。(flags & 0x03) == 0x03
: 在格式化之前,对 value 调用ascii()
。(flags & 0x04) == 0x04
: 从堆栈中弹出 fmt_spec 并使用它,否则使用空 fmt_spec。
格式化使用
PyObject_Format()
执行。结果被压入堆栈。在 3.6 版本中添加。
- MATCH_CLASS(count)¶
STACK[-1]
是一个关键字属性名称元组,STACK[-2]
是要匹配的类,STACK[-3]
是匹配主题。弹出
STACK[-1]
、STACK[-2]
和STACK[-3]
。如果STACK[-3]
是STACK[-2]
的实例,并且具有 count 和STACK[-1]
所需的位置和关键字属性,则压入一个提取的属性元组。否则,压入None
。在 3.10 版本中添加。
在 3.11 版本中变更: 以前,此指令还推入一个布尔值,表示成功(
True
)或失败(False
)。
- RESUME(where)¶
无操作。执行内部跟踪、调试和优化检查。
where
操作数标记RESUME
发生的位置0
函数的开头,它既不是生成器、协程也不是异步生成器1
在yield
表达式之后2
在yield from
表达式之后3
在await
表达式之后
在 3.11 版本中添加。
- RETURN_GENERATOR¶
从当前帧创建生成器、协程或异步生成器。用作上述可调用代码对象中的第一个指令。清除当前帧并返回新创建的生成器。
在 3.11 版本中添加。
- SEND(delta)¶
等效于
STACK[-1] = STACK[-2].send(STACK[-1])
。用于yield from
和await
语句。如果调用引发
StopIteration
,则从堆栈中弹出顶部的值,压入异常的value
属性,并将字节码计数器增加 delta。在 3.11 版本中添加。
- HAVE_ARGUMENT¶
这不是真正的指令。它标识了范围 [0,255] 中不使用其参数的指令和使用其参数的指令之间的分界线(分别为
< HAVE_ARGUMENT
和>= HAVE_ARGUMENT
)。如果您的应用程序使用伪指令,请使用
hasarg
集合。在 3.6 版本中变更: 现在每个指令都有一个参数,但指令
< HAVE_ARGUMENT
会忽略它。之前,只有指令>= HAVE_ARGUMENT
才有参数。在 3.12 版本中变更: 伪指令已添加到
dis
模块中,对于它们来说,与HAVE_ARGUMENT
的比较并不表示它们是否使用其参数。
- CALL_INTRINSIC_1¶
调用一个带有一个参数的内联函数。将
STACK[-1]
作为参数传递,并将STACK[-1]
设置为结果。用于实现非性能关键的功能。操作数决定调用哪个内联函数
操作数
描述
INTRINSIC_1_INVALID
无效
INTRINSIC_PRINT
将参数打印到标准输出。在 REPL 中使用。
INTRINSIC_IMPORT_STAR
对命名模块执行
import *
。INTRINSIC_STOPITERATION_ERROR
从
StopIteration
异常中提取返回值。INTRINSIC_ASYNC_GEN_WRAP
包装异步生成器值
INTRINSIC_UNARY_POSITIVE
执行一元
+
操作INTRINSIC_LIST_TO_TUPLE
将列表转换为元组
INTRINSIC_TYPEVAR
创建一个
typing.TypeVar
INTRINSIC_PARAMSPEC
创建一个
typing.ParamSpec
INTRINSIC_TYPEVARTUPLE
创建一个
typing.TypeVarTuple
INTRINSIC_SUBSCRIPT_GENERIC
返回
typing.Generic
用参数进行下标运算INTRINSIC_TYPEALIAS
创建一个
typing.TypeAliasType
;用于type
语句。参数是类型别名的名称、类型参数和值的元组。在 3.12 版本中添加。
- CALL_INTRINSIC_2¶
调用具有两个参数的内建函数。用于实现非性能关键的功能
arg2 = STACK.pop() arg1 = STACK.pop() result = intrinsic2(arg1, arg2) STACK.push(result)
操作数决定调用哪个内联函数
操作数
描述
INTRINSIC_2_INVALID
无效
INTRINSIC_PREP_RERAISE_STAR
计算
ExceptionGroup
从try-except*
抛出。INTRINSIC_TYPEVAR_WITH_BOUND
创建一个
typing.TypeVar
带有边界。INTRINSIC_TYPEVAR_WITH_CONSTRAINTS
创建一个
typing.TypeVar
带有约束。INTRINSIC_SET_FUNCTION_TYPE_PARAMS
设置函数的
__type_params__
属性。在 3.12 版本中添加。
伪指令
这些操作码不会出现在 Python 字节码中。它们由编译器使用,但在生成字节码之前会被替换为真实操作码或删除。
- SETUP_FINALLY(target)¶
为以下代码块设置异常处理程序。如果发生异常,值栈级别将恢复到其当前状态,控制权将转移到
target
处的异常处理程序。
- SETUP_CLEANUP(target)¶
类似于
SETUP_FINALLY
,但在发生异常时,还会将最后一条指令 (lasti
) 推送到栈中,以便RERAISE
可以恢复它。如果发生异常,帧上的值栈级别和最后一条指令将恢复到其当前状态,控制权将转移到target
处的异常处理程序。
- SETUP_WITH(target)¶
类似于
SETUP_CLEANUP
,但在发生异常时,在控制权转移到target
处的异常处理程序之前,会从栈中弹出更多项目。此变体用于
with
和async with
结构,它们将上下文管理器__enter__()
或__aenter__()
的返回值推送到栈中。
- POP_BLOCK¶
标记与最后一个
SETUP_FINALLY
、SETUP_CLEANUP
或SETUP_WITH
关联的代码块的结束。
- JUMP¶
- JUMP_NO_INTERRUPT¶
无向相对跳转指令,由汇编器替换为其定向(向前/向后)对应指令。
- LOAD_METHOD¶
优化的未绑定方法查找。作为
LOAD_ATTR
操作码发出,并在参数中设置一个标志。
操作码集合¶
这些集合用于自动检查字节码指令
Changed in version 3.12: 这些集合现在也包含伪指令和检测指令。这些是操作码,其值 >= MIN_PSEUDO_OPCODE
和 >= MIN_INSTRUMENTED_OPCODE
。
- dis.opname¶
操作名称序列,可以使用字节码进行索引。
- dis.opmap¶
将操作名称映射到字节码的字典。
- dis.cmp_op¶
所有比较操作名称的序列。
- dis.hasarg¶
使用其参数的字节码序列。
在 3.12 版本中添加。
- dis.hasconst¶
访问常量的字节码序列。
- dis.hasfree¶
访问自由变量的字节码序列。此处的“自由”是指当前作用域中被内部作用域引用的名称,或外部作用域中被此作用域引用的名称。它不包括对全局或内置作用域的引用。
- dis.hasname¶
按名称访问属性的字节码序列。
- dis.hasjrel¶
具有相对跳转目标的字节码序列。
- dis.hasjabs¶
具有绝对跳转目标的字节码序列。
- dis.haslocal¶
访问局部变量的字节码序列。
- dis.hascompare¶
布尔运算的字节码序列。
- dis.hasexc¶
设置异常处理程序的字节码序列。
在 3.12 版本中添加。