dis — Python 字节码的反汇编器 — Python 文档

来自菜鸟教程
Python/docs/3.9/library/dis
跳转至:导航、​搜索

dis — Python 字节码的反汇编器

源代码: :source:`Lib/dis.py`



dis 模块支持对 CPython bytecode 进行反汇编分析。 该模块作为输入的 CPython 字节码在文件 Include/opcode.h 中定义,并由编译器和解释器使用。

示例:给定函数 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 版更改: 添加 文件 参数。

dis.dis(x=None, *, file=None, depth=None)

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

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

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

3.4 版更改: 添加 文件 参数。

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

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

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

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

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

3.4 版更改: 添加 文件 参数。

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 版更改: 添加 文件 参数。

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

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

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

如果 first_line 不是 None,则表示反汇编代码中第一个源代码行应报告的行号。 否则,源行信息(如果有)直接从反汇编的代码对象中获取。

3.4 版中的新功能。

dis.findlinestarts(code)

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

3.6 版更改: 行号可以减少。 以前,它们总是在增加。

dis.findlabels(code)
检测原始编译字节码字符串 code 中作为跳转目标的所有偏移量,并返回这些偏移量的列表。
dis.stack_effect(opcode, oparg=None, *, jump=None)

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

如果代码有跳转目标且jumpTrue,则stack_effect()会返回跳转的堆栈效果。 如果jumpFalse,则返回不跳跃的叠加效果。 如果 jumpNone(默认),它将返回两种情况下的最大堆栈效果。

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 编译器当前生成以下字节码指令。

一般说明

一元运算

一元操作取栈顶,应用操作,并将结果压回到栈上。

二元运算

二元运算从堆栈中删除堆栈顶部 (TOS) 和第二个最顶部堆栈项 (TOS1)。 他们执行操作,并将结果放回堆栈中。

就地操作

就地操作类似于二元操作,因为它们删除 TOS 和 TOS1,并将结果推回到堆栈上,但是当 TOS1 支持时,操作就地完成,结果 TOS 可能(但没有是)原来的TOS1。

协程操作码

杂项操作码

对于所有的 :opcode:`SET_ADD`, :opcode:`LIST_APPEND`:opcode:`MAP_ADD` 指令,而添加的值或键/value 对被弹出,容器对象保留在堆栈上,以便它可用于循环的进一步迭代。

以下所有操作码都使用它们的参数。


操作码集合

这些集合用于自动检查字节码指令:

dis.opname
操作名称序列,可使用字节码索引。
dis.opmap
字典将操作名称映射到字节码。
dis.cmp_op
所有比较操作名称的顺序。
dis.hasconst
访问常量的字节码序列。
dis.hasfree
访问自由变量的字节码序列(请注意,此上下文中的“自由”指的是当前作用域中由内部作用域引用的名称或从此作用域引用的外部作用域中的名称。 它确实 包括对全局或内置范围的引用)。
dis.hasname
按名称访问属性的字节码序列。
dis.hasjrel
具有相对跳转目标的字节码序列。
dis.hasjabs
具有绝对跳转目标的字节码序列。
dis.haslocal
访问局部变量的字节码序列。
dis.hascompare
布尔运算的字节码序列。