You are trying to disassemble a string containing source code, but that's not supported by dis.dis
in Python?2. With a string argument, it treats the string as if it contained byte code (see the function disassemble_string
in dis.py
). So you are seeing nonsensical output based on misinterpreting source code as byte code.
Things are different in Python 3, where dis.dis
compiles a string argument before disassembling it:
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
In Python 2 you need to compile the code yourself before passing it to 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
What do the numbers mean? The number 1
on the far left is the line number in the source code from which this byte code was compiled. The numbers in the column on the left are the offset of the instruction within the bytecode, and the numbers on the right are the opargs. Let's look at the actual byte code:
>>> co = compile('heapq.nlargest(d,3)', '<none>', 'eval')
>>> co.co_code.encode('hex')
'6500006a010065020064000083020053'
At offset 0 in the byte code we find 65
, the opcode for LOAD_NAME
, with the oparg 0000
; then (at offset 3) 6a
is the opcode LOAD_ATTR
, with 0100
the oparg, and so on. Note that the opargs are in little-endian order, so that 0100
is the number 1. The undocumented opcode
module contains tables opname
giving you the name for each opcode, and opmap
giving you the opcode for each name:
>>> opcode.opname[0x65]
'LOAD_NAME'
The meaning of the oparg depends on the opcode, and for the full story you need to read the implementation of the CPython virtual machine in ceval.c
. For LOAD_NAME
and LOAD_ATTR
the oparg is an index into the co_names
property of the code object:
>>> co.co_names
('heapq', 'nlargest', 'd')
For LOAD_CONST
it is an index into the co_consts
property of the code object:
>>> co.co_consts
(3,)
For CALL_FUNCTION
, it is the number of arguments to pass to the function, encoded in 16 bits with the number of ordinary arguments in the low byte, and the number of keyword arguments in the high byte.