我应该如何理解dis.dis的输出?

2025-04-16 08:57:00
admin
原创
19
摘要:问题描述:我想了解如何使用dis (Python 字节码反汇编器)dis.dis 。具体来说,应该如何解释(或)的输出dis.disassemble?。这是一个非常具体的例子(在 Python 2.7.3 中):dis.dis("heapq.nsmallest(d,3)") ...

问题描述:

我想了解如何使用dis (Python 字节码反汇编器)dis.dis 。具体来说,应该如何解释(或)的输出dis.disassemble

这是一个非常具体的例子(在 Python 2.7.3 中):

dis.dis("heapq.nsmallest(d,3)")

      0 BUILD_SET             24933
      3 JUMP_IF_TRUE_OR_POP   11889
      6 JUMP_FORWARD          28019 (to 28028)
      9 STORE_GLOBAL          27756 (27756)
     12 LOAD_NAME             29811 (29811)
     15 STORE_SLICE+0  
     16 LOAD_CONST            13100 (13100)
     19 STORE_SLICE+1

我看到JUMP_IF_TRUE_OR_POP等是字节码指令(虽然有趣的是,BUILD_SET它并没有出现在这个列表中,尽管我预计它会像 一样工作BUILD_TUPLE。我认为右边的数字是内存分配,左边的数字是goto指令……我注意到它们几乎每次都增加 3(但不完全是)。

如果我包装dis.dis("heapq.nsmallest(d,3)")在一个函数中:

def f_heapq_nsmallest(d,n):
    return heapq.nsmallest(d,n)

dis.dis("f_heapq(d,3)")

      0 BUILD_TUPLE            26719
      3 LOAD_NAME              28769 (28769)
      6 JUMP_ABSOLUTE          25640
      9 <44>                                      # what is <44> ?  
     10 DELETE_SLICE+1 
     11 STORE_SLICE+1 

解决方案 1:

您正在尝试反汇编一个包含源代码的字符串,但 Python 2 不支持此功能。dis.dis如果使用字符串参数,它会将该字符串视为包含字节码(请参阅disassemble_string中的dis.py函数)。因此,您看到的输出毫无意义,因为将源代码误解为字节码。

Python 3 中的情况有所不同,它会在反汇编dis.dis字符串参数之前对其进行编译:

Python 3.2.3 (default, Aug 13 2012, 22:28:10) 
>>> import dis
>>> dis.dis('heapq.nlargest(d,3)')
  1           0 LOAD_NAME                0 (heapq) 
              3 LOAD_ATTR                1 (nlargest) 
              6 LOAD_NAME                2 (d) 
              9 LOAD_CONST               0 (3) 
             12 CALL_FUNCTION            2 
             15 RETURN_VALUE         

在 Python 2 中,您需要先自行编译代码,然后再将其传递给dis.dis

Python 2.7.3 (default, Aug 13 2012, 18:25:43) 
>>> import dis
>>> dis.dis(compile('heapq.nlargest(d,3)', '<none>', 'eval'))
  1           0 LOAD_NAME                0 (heapq)
              3 LOAD_ATTR                1 (nlargest)
              6 LOAD_NAME                2 (d)
              9 LOAD_CONST               0 (3)
             12 CALL_FUNCTION            2
             15 RETURN_VALUE        

这些数字是什么意思?最左边的数字1是编译此字节码的源代码中的行号。左侧列中的数字是字节码中指令的偏移量,右侧的数字是opargs。让我们看一下实际的字节码:

>>> co = compile('heapq.nlargest(d,3)', '<none>', 'eval')
>>> co.co_code.encode('hex')
'6500006a010065020064000083020053'

在字节码的偏移量 0 处,我们找到了65的操作码LOAD_NAME,以及相应的操作参数0000;然后(在偏移量 3 处)6a是操作码LOAD_ATTR,以及0100相应的操作参数,依此类推。注意,操作参数是小端序的,所以0100数字是 1。未公开的opcode模块包含一些表格,opname列出了每个操作码的名称,以及opmap每个名称对应的操作码:

>>> opcode.opname[0x65]
'LOAD_NAME'

oparg 的含义取决于操作码,要了解完整的内容,您需要阅读 CPython 虚拟机的实现。ceval.c对于LOAD_NAME和 , oparg 是代码对象属性LOAD_ATTR的索引:co_names

>>> co.co_names
('heapq', 'nlargest', 'd')

因为它是代码对象属性的LOAD_CONST索引:co_consts

>>> co.co_consts
(3,)

对于CALL_FUNCTION,它是传递给函数的参数的数量,以 16 位编码,低字节为普通参数的数量,高字节为关键字参数的数量。

解决方案 2:

我正在重新发布对另一个问题的回答,以确保在谷歌搜索时能找到它dis.dis()


为了完成伟大的Gareth Rees 的回答,这里只是一个逐列的小摘要,以解释反汇编字节码的输出。

例如,给定此函数:

def f(num):
    if num == 42:
        return True
    return False

这可以拆解成(Python 3.6):

(1)|(2)|(3)|(4)|          (5)         |(6)|  (7)
---|---|---|---|----------------------|---|-------
  2|   |   |  0|LOAD_FAST             |  0|(num)
   |-->|   |  2|LOAD_CONST            |  1|(42)
   |   |   |  4|COMPARE_OP            |  2|(==)
   |   |   |  6|POP_JUMP_IF_FALSE     | 12|
   |   |   |   |                      |   |
  3|   |   |  8|LOAD_CONST            |  2|(True)
   |   |   | 10|RETURN_VALUE          |   |
   |   |   |   |                      |   |
  4|   |>> | 12|LOAD_CONST            |  3|(False)
   |   |   | 14|RETURN_VALUE          |   |

每列都有特定用途:

  1. 源代码中对应的行号

  2. 可选地指示当前执行的指令(例如,当字节码来自框架对象时)

  3. JUMP表示从之前的指令到这个指令的可能的标签

  4. 字节码中与字节索引对应的地址(这些是 2 的倍数,因为 Python 3.6 对每个指令使用 2 个字节,而在以前的版本中可能会有所不同

  5. 指令名称(也称为opname ),每个指令在模块dis中都有简要说明,其实现可以在ceval.c(CPython 的核心循环)中找到

  6. 指令的参数(如果有)由 Python 内部使用,用于获取一些常量或变量、管理堆栈、跳转到特定指令等

  7. 指令论证的人性化解释

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   2379  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1510  
  PLM(产品生命周期管理)系统在企业项目管理中扮演着至关重要的角色,它能够整合产品从概念设计到退役的全流程信息,提升协同效率,降低成本。然而,项目范围蔓延是项目管理过程中常见且棘手的问题,在PLM系统环境下也不例外。范围蔓延可能导致项目进度延迟、成本超支、质量下降等一系列不良后果,严重影响项目的成功交付。因此,如何在P...
plm项目经理是做什么   16  
  PLM(产品生命周期管理)系统在现代企业的产品研发与管理过程中扮演着至关重要的角色。它不仅仅是一个管理产品数据的工具,更能在利益相关者分析以及沟通矩阵设计方面提供强大的支持。通过合理运用PLM系统,企业能够更好地识别、理解和管理与产品相关的各类利益相关者,构建高效的沟通机制,从而提升产品开发的效率与质量,增强企业的市场...
plm是什么   20  
  PLM(产品生命周期管理)项目管理对于企业产品的全生命周期规划、执行与监控至关重要。在项目推进过程中,监控进度偏差是确保项目按时、按质量完成的关键环节。五维健康检查指标体系为有效监控PLM项目进度偏差提供了全面且系统的方法,涵盖了项目的多个关键维度,有助于及时发现问题并采取针对性措施。需求维度:精准把握项目基石需求维度...
plm项目管理软件   18  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用