Alternate title:
How to really “DIS” your Python programs!
Apparently there is a Python “module” called - appropriately enough - “dis”.
Though it sounds insulting, its result is rather clever as it “disassembles” the compiled bytecode and produces the Python equivalent of an “assembler” listing.
Here’s an example:
First - The first 22 lines of my New and Improved battery test program.
#!/usr/bin/python3
import sys
from easygopigo3 import EasyGoPiGo3
from time import sleep
mybot = EasyGoPiGo3()
# Set initial values
accumulated_value = 0
count = 0
num_measurements = 20 # Number of measurements per test
sleep_time = 0.25 # How long to wait between individual measurements within a test cycle.
reference_input_voltage = 12.00
five_v_system_voltage = 0.00
measured_battery_voltage = 0.00
measured_voltage_differential = 0.00
# file1 = open("./voltage_test.txt", "a")
file1 = open("./results/voltage_test-"+str(sleep_time)+"sec.txt", "a")
def vround(x, decimal_precision=2):
[. . . .]
and the corresponding output from dis:
3 0 LOAD_CONST 0 (0)
2 LOAD_CONST 1 (None)
4 IMPORT_NAME 0 (sys)
6 STORE_NAME 0 (sys)
4 8 LOAD_CONST 0 (0)
10 LOAD_CONST 2 (('EasyGoPiGo3',))
12 IMPORT_NAME 1 (easygopigo3)
14 IMPORT_FROM 2 (EasyGoPiGo3)
16 STORE_NAME 2 (EasyGoPiGo3)
18 POP_TOP
5 20 LOAD_CONST 0 (0)
22 LOAD_CONST 3 (('sleep',))
24 IMPORT_NAME 3 (time)
26 IMPORT_FROM 4 (sleep)
28 STORE_NAME 4 (sleep)
30 POP_TOP
7 32 LOAD_NAME 2 (EasyGoPiGo3)
34 CALL_FUNCTION 0
36 STORE_NAME 5 (mybot)
10 38 LOAD_CONST 0 (0)
40 STORE_NAME 6 (accumulated_value)
11 42 LOAD_CONST 0 (0)
44 STORE_NAME 7 (count)
12 46 LOAD_CONST 4 (20)
48 STORE_NAME 8 (num_measurements)
13 50 LOAD_CONST 5 (0.25)
52 STORE_NAME 9 (sleep_time)
14 54 LOAD_CONST 6 (12.0)
56 STORE_NAME 10 (reference_input_voltage)
15 58 LOAD_CONST 7 (0.0)
60 STORE_NAME 11 (five_v_system_voltage)
16 62 LOAD_CONST 7 (0.0)
64 STORE_NAME 12 (measured_battery_voltage)
17 66 LOAD_CONST 7 (0.0)
68 STORE_NAME 13 (measured_voltage_differential)
20 70 LOAD_NAME 14 (open)
72 LOAD_CONST 8 ('./results/voltage_test-')
74 LOAD_NAME 15 (str)
76 LOAD_NAME 9 (sleep_time)
78 CALL_FUNCTION 1
80 BINARY_ADD
82 LOAD_CONST 9 ('sec.txt')
84 BINARY_ADD
86 LOAD_CONST 10 ('a')
88 CALL_FUNCTION 2
90 STORE_NAME 16 (file1)
22 92 LOAD_CONST 26 ((2,))
94 LOAD_CONST 12 (<code object vround at 0xb641b338, file "/home/pi/Project_Files/Projects/battery_test/batt_test.py", line 22>)
96 LOAD_CONST 13 ('vround')
98 MAKE_FUNCTION 1
100 STORE_NAME 17 (vround)
The columns go like this:
Column:
- The line number within the source file, comment lines being omitted.
This is why the first line number is “3” - the first two lines in the source code are comments. - The line number or virtual memory location, (starting from zero), that the statement is on - most statements take two bytes so the line numbers increment by two.
- The “assembler mnemonic” for that instruction.
- The “index” that points to a particular value or thing.
You will notice that once something is defined and given an index, the index for that thing never changes. - What that index refers to in human-readable form.
Here is the current version of my battery test program, (I’m still working on it, trying out techniques I will use to refactor the New Remote Camera Robot programs), and the associated “assembler” file.
batt_test (1).py (2.7 KB)
battery_test.asm.txt (13.7 KB)
I shudder to think what the New Remote Camera Robot file would look like disassembled!