# `dis` --- Python bytecode的反組譯器

原始碼：Lib/dis.py

`dis` 模組支援反組譯分析 CPython bytecode。CPython bytecode 作為輸入的模組被定義於 `Include/opcode.h` 並且被編譯器和直譯器所使用。

CPython implementation detail: 字节码是 CPython 解释器的实现细节。不保证不会在Python版本之间添加、删除或更改字节码。不应考虑将此模块的跨 Python VM 或 Python 版本的使用。

3.6 版更變: 每条指令使用2个字节。以前字节数因指令而异。

示例：给出函数 `myfunc()`:

    def myfunc(alist):
        return len(alist)

可以使用以下命令显示 `myfunc()` 的反汇编

    >>> dis.dis(myfunc)
      2           0 LOAD_GLOBAL              0 (len)
                  2 LOAD_FAST                0 (alist)
                  4 CALL_FUNCTION            1
                  6 RETURN_VALUE

("2" 是行号)。

## 字节码分析

3.4 版新加入.

字节码分析 API 允许将 Python 代码片段包装在 `Bytecode` 对象中，以便轻松访问已编译代码的详细信息。

class `dis.``Bytecode`(x, *, first_line=None, current_offset=None)

  分析的字节码对应于函数、生成器、异步生成器、协程、方法、源代码字符串或代码对象（由 `compile()` 返回）。

  这是下面列出的许多函数的便利包装，最值得注意的是 `get_instructions()` ，迭代于 `Bytecode` 的实例产生字节码操作 `Instruction` 的实例。

  如果 first_line 不是 `None` ，则表示应该为反汇编代码中的第一个源代码行报告的行号。否则，源行信息（如果有的话）直接来自反汇编的代码对象。

  如果 current_offset 不是 `None` ，则它指的是反汇编代码中的指令偏移量。设置它意味着 `dis()` 将针对指定的操作码显示“当前指令”标记。

  classmethod `from_traceback`(tb)

    从给定回溯构造一个 `Bytecode` 实例，将设置 current_offset 为异常负责的指令。

  `codeobj`

    已编译的代码对象。

  `first_line`

    代码对象的第一个源代码行（如果可用）

  `dis`()

    返回字节码操作的格式化视图（与 `dis.dis()` 打印相同，但作为多行字符串返回）。

  `info`()

    返回带有关于代码对象的详细信息的格式化多行字符串，如 `code_info()` 。

  3.7 版更變: 现在可以处理协程和异步生成器对象。

示例:

    >>> bytecode = dis.Bytecode(myfunc)
    >>> for instr in bytecode:
    ...     print(instr.opname)
    ...
    LOAD_GLOBAL
    LOAD_FAST
    CALL_FUNCTION
    RETURN_VALUE

## 分析函数

`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)

  反汇编 x 对象。 x 可以表示模块、类、方法、函数、生成器、异步生成器、协程、代码对象、源代码字符串或原始字节码的字节序列。对于模块，它会反汇编所有功能。对于一个类，它反汇编所有方法（包括类和静态方法）。对于代码对象或原始字节码序列，它每字节码指令打印一行。它还递归地反汇编嵌套代码对象（推导式代码，生成器表达式和嵌套函数，以及用于构建嵌套类的代码）。在被反汇编之前，首先使用 `compile()` 内置函数将字符串编译为代码对象。如果未提供任何对象，则此函数会反汇编最后一次回溯。

  如果提供的话，反汇编将作为文本写入提供的 file 参数，否则写入 `sys.stdout` 。

  递归的最大深度受 depth 限制，除非它是 `None` 。 `depth=0` 表示没有递归。

  3.4 版更變: 添加 file 形参。

  3.7 版更變: 实现了递归反汇编并添加了 depth 参数。

  3.7 版更變: 现在可以处理协程和异步生成器对象。

`dis.``distb`(tb=None, *, file=None)

  如果没有传递，则使用最后一个回溯来反汇编回溯的堆栈顶部函数。 指示了导致异常的指令。

  如果提供的话，反汇编将作为文本写入提供的 file 参数，否则写入 `sys.stdout` 。

  3.4 版更變: 添加 file 形参。

`dis.``disassemble`(code, lasti=-1, *, file=None)
`dis.``disco`(code, lasti=-1, *, file=None)

  反汇编代码对象，如果提供了 lasti ，则指示最后一条指令。输出分为以下几列：

  1. 行号，用于每行的第一条指令

  2. 当前指令，表示为 `-->` ，

  3. 一个标记的指令，用 `>>` 表示，

  4. 指令的地址，

  5. 操作码名称，

  6. 操作参数，和

  7. 括号中参数的解释。

  参数解释识别本地和全局变量名称、常量值、分支目标和比较运算符。

  如果提供的话，反汇编将作为文本写入提供的 file 参数，否则写入 `sys.stdout` 。

  3.4 版更變: 添加 file 形参。

`dis.``get_instructions`(x, *, first_line=None)

  在所提供的函数、方法、源代码字符串或代码对象中的指令上返回一个迭代器。

  迭代器生成一系列 `Instruction` ，命名为元组，提供所提供代码中每个操作的详细信息。

  如果 first_line 不是 `None` ，则表示应该为反汇编代码中的第一个源代码行报告的行号。否则，源行信息（如果有的话）直接来自反汇编的代码对象。

  3.4 版新加入.

`dis.``findlinestarts`(code)

  此生成器函数使用代码对象 code 的 `co_firstlineno` 和 `co_lnotab` 属性来查找源代码中行开头的偏移量。它们生成为 `(offset, lineno)` 对。请参阅 objects/lnotab_notes.txt ，了解 `co_lnotab` 格式以及如何解码它。

  3.6 版更變: 行号可能会减少。 以前，他们总是在增加。

`dis.``findlabels`(code)

  检测作为跳转目标的原始编译后字节码字符串 code 中的所有偏移量，并返回这些偏移量的列表。

`dis.``stack_effect`(opcode, oparg=None, *, jump=None)

  使用参数 oparg 计算 opcode 的堆栈效果。

  如果代码有一个跳转目标并且 jump 是 `True` ，则 `drag_effect()` 将返回跳转的堆栈效果。如果 jump 是 `False` ，它将返回不跳跃的堆栈效果。如果 jump 是 `None` （默认值），它将返回两种情况的最大堆栈效果。

  3.4 版新加入.

  3.8 版更變: 添加 jump 参数。

## Python字节码说明

`get_instructions()` 函数和 `Bytecode` 类提供字节码指令的详细信息的 `Instruction` 实例：

class `dis.``Instruction`

  字节码操作的详细信息

  `opcode`

    操作的数字代码，对应于下面列出的操作码值和 操作码集合 中的字节码值。

  `opname`

    人类可读的操作名称

  `arg`

    操作的数字参数（如果有的话），否则为 `None`

  `argval`

    已解析的 arg 值（如果已知），否则与 arg 相同

  `argrepr`

    人类可读的操作参数描述

  `offset`

    在字节码序列中启动操作索引

  `starts_line`

    行由此操作码（如果有）启动，否则为 `None`

  `is_jump_target`

    如果其他代码跳到这里，则为 `True` ，否则为 `False`

  3.4 版新加入.

Python编译器当前生成以下字节码指令。

一般指令

`NOP`

  什么都不做。 用作字节码优化器的占位符。

`POP_TOP`

  删除堆栈顶部（TOS）项。

`ROT_TWO`

  交换两个最顶层的堆栈项。

`ROT_THREE`

  将第二个和第三个堆栈项向上提升一个位置，顶项移动到位置三。

`ROT_FOUR`

  将第二个，第三个和第四个堆栈项向上提升一个位置，将顶项移动到第四个位置。

  3.8 版新加入.

`DUP_TOP`

  复制堆栈顶部的引用。

  3.2 版新加入.

`DUP_TOP_TWO`

  复制堆栈顶部的两个引用，使它们保持相同的顺序。

  3.2 版新加入.

一元操作

一元操作获取堆栈顶部元素，应用操作，并将结果推回堆栈。

`UNARY_POSITIVE`

  实现 `TOS = +TOS` 。

`UNARY_NEGATIVE`

  实现 `TOS = -TOS` 。

`UNARY_NOT`

  实现 `TOS = not TOS` 。

`UNARY_INVERT`

  实现 `TOS = ~TOS` 。

`GET_ITER`

  实现 `TOS = iter(TOS)` 。

`GET_YIELD_FROM_ITER`

  如果 `TOS` 是一个 generator iterator 或 coroutine 对象则保持原样。否则实现 `TOS = iter(TOS)` 。

  3.5 版新加入.

二元操作

二元操作从堆栈中删除堆栈顶部（TOS）和第二个最顶层堆栈项（TOS1）。 它们执行操作，并将结果放回堆栈。

`BINARY_POWER`

  实现 `TOS = TOS1 ** TOS` 。

`BINARY_MULTIPLY`

  实现 `TOS = TOS1 * TOS` 。

`BINARY_MATRIX_MULTIPLY`

  实现 `TOS = TOS1 @ TOS` 。

  3.5 版新加入.

`BINARY_FLOOR_DIVIDE`

  实现 `TOS = TOS1 // TOS`。

`BINARY_TRUE_DIVIDE`

  实现 `TOS = TOS1 / TOS` 。

`BINARY_MODULO`

  实现 `TOS = TOS1 % TOS` 。

`BINARY_ADD`

  实现 `TOS = TOS1 + TOS` 。

`BINARY_SUBTRACT`

  实现 `TOS = TOS1 - TOS` 。

`BINARY_SUBSCR`

  实现 `TOS = TOS1[TOS]` 。

`BINARY_LSHIFT`

  实现 `TOS = TOS1 << TOS` 。

`BINARY_RSHIFT`

  实现 `TOS = TOS1 >> TOS` 。

`BINARY_AND`

  实现 `TOS = TOS1 & TOS` 。

`BINARY_XOR`

  实现 `TOS = TOS1 ^ TOS` 。

`BINARY_OR`

  实现 `TOS = TOS1 | TOS` 。

就地操作

就地操作就像二元操作，因为它们删除了TOS和TOS1，并将结果推回到堆栈上，但是当TOS1支持它时，操作就地完成，并且产生的TOS可能是（但不一定） 原来的TOS1。

`INPLACE_POWER`

  就地实现 `TOS = TOS1 ** TOS` 。

`INPLACE_MULTIPLY`

  就地实现 `TOS = TOS1 * TOS` 。

`INPLACE_MATRIX_MULTIPLY`

  就地实现 `TOS = TOS1 @ TOS` 。

  3.5 版新加入.

`INPLACE_FLOOR_DIVIDE`

  就地实现 `TOS = TOS1 // TOS` 。

`INPLACE_TRUE_DIVIDE`

  就地实现 `TOS = TOS1 / TOS` 。

`INPLACE_MODULO`

  就地实现 `TOS = TOS1 % TOS` 。

`INPLACE_ADD`

  就地实现 `TOS = TOS1 + TOS` 。

`INPLACE_SUBTRACT`

  就地实现 `TOS = TOS1 - TOS` 。

`INPLACE_LSHIFT`

  就地实现 `TOS = TOS1 << TOS` 。

`INPLACE_RSHIFT`

  就地实现 `TOS = TOS1 >> TOS` 。

`INPLACE_AND`

  就地实现 `TOS = TOS1 & TOS` 。

`INPLACE_XOR`

  就地实现 `TOS = TOS1 ^ TOS` 。

`INPLACE_OR`

  就地实现 `TOS = TOS1 | TOS` 。

`STORE_SUBSCR`

  实现 `TOS1[TOS] = TOS2` 。

`DELETE_SUBSCR`

  实现 `del TOS1[TOS]` 。

协程操作码

`GET_AWAITABLE`

  实现 `TOS = get_awaitable(TOS)` ，其中 `get_awaitable(o)` 返回 `o` 如果 `o` 是一个有 CO_ITERABLE_COROUTINE 标志的协程对象或生成器对象，否则解析 `o.__await__` 。

  3.5 版新加入.

`GET_AITER`

  实现 `TOS = TOS.__aiter__()` 。

  3.5 版新加入.

  3.7 版更變: 已经不再支持从 `__aiter__` 返回可等待对象。

`GET_ANEXT`

  实现 `PUSH(get_awaitable(TOS.__anext__()))` 。参见 `GET_AWAITABLE` 获取更多 `get_awaitable` 的细节

  3.5 版新加入.

`END_ASYNC_FOR`

  终止一个 `async for` 循环。处理等待下一个项目时引发的异常。如果 TOS 是 `StopAsyncIteration`， 从堆栈弹出7个值，并使用后三个恢复异常状态。否则，使用堆栈中的三个值重新引发异常。从块堆栈中删除异常处理程序块。

  3.8 版新加入.

`BEFORE_ASYNC_WITH`

  从栈顶对象解析 `__aenter__` 和 `__aexit__` 。将 `__aexit__` 和 `__aenter__()` 的结果推入堆栈。

  3.5 版新加入.

`SETUP_ASYNC_WITH`

  创建一个新的帧对象。

  3.5 版新加入.

其他操作码

`PRINT_EXPR`

  实现交互模式的表达式语句。TOS从堆栈中被移除并打印。在非交互模式下，表达式语句以 `POP_TOP` 终止。

`SET_ADD`(i)

  调用 `set.add(TOS1[-i], TOS)` 。 用于实现集合推导。

`LIST_APPEND`(i)

  调用 `list.append(TOS[-i], TOS)` 。 用于实现列表推导。

`MAP_ADD`(i)

  调用 `dict.__setitem__(TOS1[-i], TOS1, TOS)` 。 用于实现字典推导。

  3.1 版新加入.

  3.8 版更變: 映射值为 TOS ，映射键为 TOS1 。之前，它们被颠倒了。

对于所有 `SET_ADD` 、 `LIST_APPEND` 和 `MAP_ADD` 指令，当弹出添加的值或键值对时，容器对象保留在堆栈上，以便它可用于循环的进一步迭代。

`RETURN_VALUE`

  返回 TOS 到函数的调用者。

`YIELD_VALUE`

  弹出 TOS 并从一个 generator 生成它。

`YIELD_FROM`

  弹出 TOS 并将其委托给它作为 generator 的子迭代器。

  3.3 版新加入.

`SETUP_ANNOTATIONS`

  检查 `__annotations__` 是否在 `locals()` 中定义，如果没有，它被设置为空 `dict` 。只有在类或模块体静态地包含 variable annotations 时才会发出此操作码。

  3.6 版新加入.

`IMPORT_STAR`

  将所有不以 `'_'` 开头的符号直接从模块 TOS 加载到局部命名空间。加载所有名称后弹出该模块。这个操作码实现了 `from module import *` 。

`POP_BLOCK`

  从块堆栈中删除一个块。有一块堆栈，每帧用于表示 `try` 语句等。

`POP_EXCEPT`

  从块堆栈中删除一个块。 弹出的块必须是异常处理程序块，在进入 except 处理程序时隐式创建。除了从帧堆栈弹出无关值之外，最后三个弹出值还用于恢复异常状态。

`RERAISE`

  重新引发当前位于栈顶的异常。

  3.9 版新加入.

`WITH_EXCEPT_START`

  调用堆栈中 7 号位置上的函数并附带栈顶位置的三项作为参数。 用来在 `with` 语句内发生异常时实现调用 `context_manager.__exit__(*exc_info())`。

  3.9 版新加入.

`LOAD_ASSERTION_ERROR`

  将 `AssertionError` 推入栈顶。 由 `assert` 语句使用。

  3.9 版新加入.

`LOAD_BUILD_CLASS`

  将 `builtins .__ build_class__()` 推到堆栈上。它之后被 `CALL_FUNCTION` 调用来构造一个类。

`SETUP_WITH`(delta)

  此操作码在 with 块开始之前执行多个操作。首先，它从上下文管理器加载 `__exit__()` 并将其推入到堆栈以供以后被 `WITH_CLEANUP_START` 使用。然后，调用 `__enter__()` ，并推入指向 delta 的 finally 块。最后，调用 `__enter__()` 方法的结果被压入堆栈。一个操作码将忽略它（ `POP_TOP` ），或将其存储在一个或多个变量（ `STORE_FAST` 、 `STORE_NAME` 或 `UNPACK_SEQUENCE` ）中。

  3.2 版新加入.

以下所有操作码均使用其参数。

`STORE_NAME`(namei)

  实现 `name = TOS`。 namei 是 name 在代码对象的 `co_names` 属性中的索引。 在可能的情况下，编译器会尝试使用 `STORE_FAST` 或 `STORE_GLOBAL`。

`DELETE_NAME`(namei)

  实现 `del name` ，其中 namei 是代码对象的 `co_names` 属性的索引。

`UNPACK_SEQUENCE`(count)

  将 TOS 解包为 count 个单独的值，它们将按从右至左的顺序被放入堆栈。

`UNPACK_EX`(counts)

  实现使用带星号的目标进行赋值：将 TOS 中的可迭代对象解包为单独的值，其中值的总数可以小于可迭代对象中的项数：新值之一将是由所有剩余项构成的列表。

  counts 的低字节是列表值之前的值的数量，counts 中的高字节则是之后的值的数量。 结果值会按从右至左的顺序入栈。

`STORE_ATTR`(namei)

  实现 `TOS.name = TOS1`，其中 namei 是 name 在 `co_names` 中的索引号。

`DELETE_ATTR`(namei)

  实现 `del TOS.name`，使用 namei 作为 `co_names` 中的索引号。

`STORE_GLOBAL`(namei)

  类似于 `STORE_NAME` 但会将 name 存储为全局变量。

`DELETE_GLOBAL`(namei)

  类似于 `DELETE_NAME` 但会删除一个全局变量。

`LOAD_CONST`(consti)

  将 `co_consts[consti]` 推入栈顶。

`LOAD_NAME`(namei)

  将与 `co_names[namei]` 相关联的值推入栈顶。

`BUILD_TUPLE`(count)

  创建一个使用了来自栈的 count 个项的元组，并将结果元组推入栈顶。

`BUILD_LIST`(count)

  类似于 `BUILD_TUPLE` 但会创建一个列表。

`BUILD_SET`(count)

  类似于 `BUILD_TUPLE` 但会创建一个集合。

`BUILD_MAP`(count)

  将一个新字典对象推入栈顶。 弹出 `2 * count` 项使得字典包含 count 个条目: `{..., TOS3: TOS2, TOS1: TOS}`。

  3.5 版更變: 字典是根据栈中的项创建而不是创建一个预设大小包含 count 项的空字典。

`BUILD_CONST_KEY_MAP`(count)

  `BUILD_MAP` 版本专用于常量键。 弹出的栈顶元素包含一个由键构成的元组，然后从 `TOS1` 开始从构建字典的值中弹出 count 个值。

  3.6 版新加入.

`BUILD_STRING`(count)

  拼接 count 个来自栈的字符串并将结果字符串推入栈顶。

  3.6 版新加入.

`LIST_TO_TUPLE`

  > 从堆栈中弹出一个列表并推入一个包含相同值的元组。

  3.9 版新加入.

`LIST_EXTEND`(i)

  调用 `list.extend(TOS1[-i], TOS)`。 用于构建列表。

  3.9 版新加入.

`SET_UPDATE`(i)

  调用 `set.update(TOS1[-i], TOS)`。 用于构建集合。

  3.9 版新加入.

`DICT_UPDATE`(i)

  调用 `dict.update(TOS1[-i], TOS)`。 用于构建字典。

  3.9 版新加入.

`DICT_MERGE`

  > 类似于 `DICT_UPDATE` 但对于重复的键会引发异常。

  3.9 版新加入.

`LOAD_ATTR`(namei)

  将 TOS 替换为 `getattr(TOS, co_names[namei])`。

`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]`。 会弹出 TOS 和 TOS1 以提供 fromlist 和 level 参数给 `__import__()`。 模块对象会被推入栈顶。 当前命名空间不受影响：对于一条标准 import 语句，会执行后续的 `STORE_FAST` 指令来修改命名空间。

`IMPORT_FROM`(namei)

  从在 TOS 内找到的模块中加载属性 `co_names[namei]`。 结果对象会被推入栈顶，以便由后续的 `STORE_FAST` 指令来保存。

`JUMP_FORWARD`(delta)

  将字节码计数器的值增加 delta。

`POP_JUMP_IF_TRUE`(target)

  如果 TOS 为真值，则将字节码计数器的值设为 target。 TOS 会被弹出。

  3.1 版新加入.

`POP_JUMP_IF_FALSE`(target)

  如果 TOS 为假值，则将字节码计数器的值设为 target。 TOS 会被弹出。

  3.1 版新加入.

`JUMP_IF_NOT_EXC_MATCH`(target)

  > 检测堆栈中的第二个值是否为匹配 TOS 的异常，如果不是则会跳转。 从堆栈中弹出两个值。

  3.9 版新加入.

`JUMP_IF_TRUE_OR_POP`(target)

  如果 TOS 为真值，则将字节码计数器的值设为 target 并将 TOS 留在栈顶。 否则（如 TOS 为假值），TOS 会被弹出。

  3.1 版新加入.

`JUMP_IF_FALSE_OR_POP`(target)

  如果 TOS 为假值，则将字节码计数器的值设为 target 并将 TOS 留在栈顶。 否则（如 TOS 为假值），TOS 会被弹出。

  3.1 版新加入.

`JUMP_ABSOLUTE`(target)

  将字节码计数器的值设为 target。

`FOR_ITER`(delta)

  TOS 是一个 iterator。 请调用其 `__next__()` 方法。 如果此操作产生了一个新值，则将其推入栈顶（将迭代器留在其下方）。 如果迭代器提示已耗尽，TOS 会被弹出，并且字节码计数器将增加 delta。

`LOAD_GLOBAL`(namei)

  加载名称为 `co_names[namei]` 的全局对象推入栈顶。

`SETUP_FINALLY`(delta)

  将一个来自 try-finally 或 try-except 子句的 try 代码块推入代码块栈顶。 相对 finally 代码块或第一个 except 代码块 delta 个点数。

`LOAD_FAST`(var_num)

  将指向局部对象 `co_varnames[var_num]` 的引用推入栈顶。

`STORE_FAST`(var_num)

  将 TOS 存放到局部对象 `co_varnames[var_num]`。

`DELETE_FAST`(var_num)

  移除局部对象 `co_varnames[var_num]`。

`LOAD_CLOSURE`(i)

  将一个包含在单元的第 i 个空位中的对单元的引用推入栈顶并释放可用的存储空间。 如果 i 小于 co_cellvars 的长度则变量的名称为 `co_cellvars[i]`。 否则为 `co_freevars[i - len(co_cellvars)]`。

`LOAD_DEREF`(i)

  加载包含在单元的第 i 个空位中的单元并释放可用的存储空间。 将一个对单元所包含对象的引用推入栈顶。

`LOAD_CLASSDEREF`(i)

  类似于 `LOAD_DEREF` 但在查询单元之前会首先检查局部对象字典。 这被用于加载类语句体中的自由变量。

  3.4 版新加入.

`STORE_DEREF`(i)

  将 TOS 存放到包含在单元的第 i 个空位中的单元内并释放可用存储空间。

`DELETE_DEREF`(i)

  清空包含在单元的第 i 个空位中的单元并释放可用存储空间。 被用于 `del` 语句。

  3.2 版新加入.

`RAISE_VARARGS`(argc)

  使用 `raise` 语句的 3 种形式之一引发异常，具体形式取决于 argc 的值：

  - 0: `raise` (重新引发之前的异常)

  - 1: `raise TOS` (在 `TOS` 上引发异常实例或类型)

  - 2: `raise TOS1 from TOS` (在 `TOS1` 上引发异常实例或类型并将 `__cause__` 设为 `TOS`)

`CALL_FUNCTION`(argc)

  调用一个可调用对象并传入位置参数。 argc 指明位置参数的数量。 栈顶包含位置参数，其中最右边的参数在最顶端。 在参数之下是一个待调用的可调用对象。 `CALL_FUNCTION` 会从栈中弹出所有参数以及可调用对象，附带这些参数调用该可调用对象，并将可调用对象所返回的返回值推入栈顶。

  3.6 版更變: 此操作码仅用于附带位置参数的调用。

`CALL_FUNCTION_KW`(argc)

  调用一个可调用对象并传入位置参数（如果有的话）和关键字参数。 argc 指明位置参数和关键字参数的总数量。 栈顶元素包含一个关键字参数名称的元组，名称必须为字符串。 在元组之下是与元组顺序相对应的关键字参数值。 在它之下则是位置参数，其中最右边的参数在最顶端。 在参数之下是要调用的可调用对象。 `CALL_FUNCTION_KW` 会从栈中弹出所有参数及可调用对象，附带这些参数调用该可调用对象，并将可调用对象所返回的返回值推入栈顶。

  3.6 版更變: 关键字参数会被打包为一个元组而非字典，argc 指明参数的总数量。

`CALL_FUNCTION_EX`(flags)

  调用一个可调用对象并附带位置参数和关键字参数变量集合。 如果设置了 flags 的最低位，则栈顶包含一个由额外关键字参数组成的映射对象。 在调用该可调用对象之前，映射对象和可迭代对象会被分别“解包”并将它们的内容分别作为关键字参数和位置参数传入。 `CALL_FUNCTION_EX` 会中栈中弹出所有参数及可调用对象，附带这些参数调用该可调用对象，并将可调用对象所返回的返回值推入栈顶。

  3.6 版新加入.

`LOAD_METHOD`(namei)

  从 TOS 对象加载一个名为 `co_names[namei]` 的方法。 TOS 将被弹出。 此字节码可区分两种情况：如果 TOS 有一个名称正确的方法，字节码会将未绑定方法和 TOS 推入栈顶。 TOS 将在调用未绑定方法时被用作 `CALL_METHOD` 的第一个参数 (`self`)。 否则会将 `NULL` 和属性查找所返回的对象推入栈顶。

  3.7 版新加入.

`CALL_METHOD`(argc)

  调用一个方法。 argc 是位置参数的数量。 关键字参数不受支持。 此操作码被设计用于配合 `LOAD_METHOD` 使用。 位置参数放在栈顶。 在它们之下放在栈中的是由 `LOAD_METHOD` 所描述的两个条目（或者是 `self` 和一个未绑定方法对象，或者是 `NULL` 和一个任意可调用对象）。 它们会被全部弹出并将返回值推入栈顶。

  3.7 版新加入.

`MAKE_FUNCTION`(flags)

  将一个新函数对象推入栈顶。 从底端到顶端，如果参数带有指定的旗标值则所使用的栈必须由这些值组成。

  - `0x01` 一个默认值的元组，用于按位置排序的仅限位置形参以及位置或关键字形参

  - `0x02` 一个仅限关键字形参的默认值的字典

  - `0x04` 是一个标注字典

  - `0x08` 一个包含用于自由变量的单元的元组，生成一个闭包

  - 与函数相关联的代码 (在 TOS1)

  - 函数的 qualified name (在 TOS)

`BUILD_SLICE`(argc)

  将一个切片对象推入栈顶。 argc 必须为 2 或 3。 如果为 2，则推入 `slice(TOS1, TOS)`；如果为 3，则推入 `slice(TOS2, TOS1, TOS)`。 请参阅 `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 版新加入.

`HAVE_ARGUMENT`

  这不是一个真正的操作码。 它用于标明使用参数和不使用参数的操作码 (分别为 `< HAVE_ARGUMENT` 和 `>= HAVE_ARGUMENT`) 之间的分隔线。

  3.6 版更變: 现在每条指令都带有参数，但操作码 `< HAVE_ARGUMENT` 会忽略它。 之前仅限操作码 `>= HAVE_ARGUMENT` 带有参数。

## 操作码集合

提供这些集合用于字节码指令的自动内省：

`dis.``opname`

  操作名称的序列，可使用字节码来索引。

`dis.``opmap`

  映射操作名称到字节码的字典

`dis.``cmp_op`

  所有比较操作名称的序列。

`dis.``hasconst`

  访问常量的字节码序列。

`dis.``hasfree`

  访问自由变量的字节码序列（请注意这里所说的‘自由’是指在当前作用域中被内部作用域所引用的名称，或在外部作用域中被此作用域所引用的名称。 它 并不 包括对全局或内置作用域的引用）。

`dis.``hasname`

  按名称访问属性的字节码序列。

`dis.``hasjrel`

  具有相对跳转目标的字节码序列。

`dis.``hasjabs`

  具有绝对跳转目标的字节码序列。

`dis.``haslocal`

  访问局部变量的字节码序列。

`dis.``hascompare`

  布尔运算的字节码序列。