我应该如何理解dis.dis的输出?
我想了解如何使用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
-
您正在尝试拆解内含源代码的字符串,但是这不支持
dis.dis
在Python
2.用字符串参数,它把字符串,如果它包含字节码(见函数disassemble_string
中dis.py
)。因此,您会看到基于将源代码误解为字节码而产生的无意义的输出。Python 3中的情况有所不同,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处找到了oparg
65
的操作码; 那么(在偏移量3处)是操作码,操作参数,以此类推。请注意,opargs的顺序为little-
endian,即数字1。未记录的模块包含一些表,这些表为您提供每个操作码的名称,并为您提供每个名称的操作码:LOAD_NAME``0000``6a``LOAD_ATTR``0100``0100``opcode``opname``opmap
>>> opcode.opname[0x65] 'LOAD_NAME'
oparg的含义取决于操作码,对于全文,您需要阅读中的CPython虚拟机的实现
ceval.c
。ForLOAD_NAME
和LOAD_ATTR
oparg是co_names
代码对象属性的索引:>>> co.co_names ('heapq', 'nlargest', 'd')
因为
LOAD_CONST
它是co_consts
代码对象属性的索引:>>> co.co_consts (3,)
对于
CALL_FUNCTION
,它是传递给函数的参数数目,以16位编码,低字节为普通参数的数目,高字节为关键字参数的数目。