首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >我应该如何理解dis.dis的输出?

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

Stack Overflow用户
提问于 2012-10-01 12:14:33
回答 1查看 22.9K关注 0票数 100

我想了解如何使用dis ( Python字节码的演示程序)。具体来说,应该如何解释dis.dis (或dis.disassemble)的输出?

下面是一个非常具体的示例(在Python2.7.3中):

代码语言:javascript
复制
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没有出现在这个列表中,尽管我希望它可以作为http://docs.python.org/library/dis.html#opcode-BUILD_TUPLE工作)。我认为右边的数字是内存分配,左边的数字是转到数字.我注意到它们几乎每次增加3次(但不完全)。

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

代码语言:javascript
复制
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 
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-10-01 12:24:17

您正在试图反汇编包含源代码的字符串,但是Python2中的dis.dis不支持这个字符串。使用string参数,它将字符串视为包含字节代码(参见函数dis.py)。因此,您将看到基于将源代码错误解释为字节代码的无意义输出。

在Python3中,情况不同,在分解之前,编译字符串参数。会这样做:

代码语言:javascript
复制
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         

在Python2中,您需要在将代码传递给dis.dis之前自己编译它。

代码语言:javascript
复制
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。让我们看一下实际的字节码:

代码语言:javascript
复制
>>> co = compile('heapq.nlargest(d,3)', '<none>', 'eval')
>>> co.co_code.encode('hex')
'6500006a010065020064000083020053'

在字节码中的偏移量为0时,我们发现65LOAD_NAME的操作码,带有oparg 0000;然后(在偏移量3处) 6a是操作码LOAD_ATTR0100是oparg,依此类推。请注意,opargs的顺序不大,所以0100是数字1。无文档的opcode模块包含表opname,给出每个操作码的名称,opmap为每个名称提供操作码:

代码语言:javascript
复制
>>> opcode.opname[0x65]
'LOAD_NAME'

oparg的含义取决于操作码,关于整个故事,您需要阅读CPython虚拟机ceval.c的实现。对于LOAD_NAMELOAD_ATTR,oparg是代码对象的co_names属性的索引:

代码语言:javascript
复制
>>> co.co_names
('heapq', 'nlargest', 'd')

对于LOAD_CONST,它是代码对象的co_consts属性的索引:

代码语言:javascript
复制
>>> co.co_consts
(3,)

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

票数 117
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12673074

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档