Disassembling Python bytecode
A reference guide for disassembling Python bytecode.
Example:⌗
>>> def test(value):
... return len(value)
...
>>> import dis
>>> dis.dis(test)
2 0 LOAD_GLOBAL 0 (len)
2 LOAD_FAST 0 (value)
4 CALL_FUNCTION 1
6 RETURN_VALUE
Explanation:⌗
(1) | (2) | (3) | (4) | (5) | (6) | (7) |
---|---|---|---|---|---|---|
2 | 0 | LOAD_GLOBAL | 0 | (len) | ||
2 | LOAD_FAST | 0 | (value) | |||
4 | CALL_FUNCTION | 1 | ||||
6 | RETURN_VALUE |
The columns returned are the following:
- The corresponding line number in the source code
- Optionally indicates the current instruction executed (when the bytecode comes from a frame object for example)
- A label which denotes a possible
JUMP
from an earlier instruction to this one - The address in the bytecode which corresponds to the byte index (those are multiples of 2 because Python 3.6 use 2 bytes for each instruction, while it could vary in previous versions):
>>> code = test.__code__.co_code
>>> code
b't\x00|\x00\x83\x01S\x00'
>>> l = list(code)
>>> l
[116, 0, 124, 0, 131, 1, 83, 0]
>>> l[0]
116
>>> l[2]
124
>>> l[4]
131
>>> l[6]
83
- The instruction name (also called opname), each one is briefly explained in the
dis
module:
>>> dis.opname[116]
'LOAD_GLOBAL'
>>> dis.opname[124]
'LOAD_FAST'
>>> dis.opname[131]
'CALL_FUNCTION'
>>> dis.opname[83]
'RETURN_VALUE'
- The argument (if any) of the instruction which is used internally by Python to fetch some constants or variables, manage the stack, jump to a specific instruction, etc.
>>> test.__code__.co_names[0]
'len'
>>> test.__code__.co_varnames[0]
'value'
- The human-friendly interpretation of the instruction argument
Some examples for a bytecode operations:
>>> test.__code__
<code object test at 0x7f9905577e40, file "<stdin>", line 1>
>>> test.__code__.co_filename
'<stdin>'
>>> test.__code__.co_consts
(None,)
>>> test.__code__.co_varnames
('value',)
>>> test.__code__.co_names
('len',)
>>> test.__code__.co_consts
(None,)
>>> test.__code__.co_argcount
1
>>> test.__code__.co_code
b't\x00|\x00\x83\x01S\x00'
>>> list(test.__code__.co_code)
[116, 0, 124, 0, 131, 1, 83, 0]
>>> dis.opname[116]
'LOAD_GLOBAL'
>>> dis.opmap['LOAD_GLOBAL']
116
Read other posts