Skip to content

Commit abf3532

Browse files
committed
dis
Doesn't feel worth adding a cross-reference for this section.
1 parent 8696b44 commit abf3532

File tree

2 files changed

+123
-130
lines changed

2 files changed

+123
-130
lines changed

episodes/optimisation-using-python.md

Lines changed: 0 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -150,134 +150,6 @@ operatorSearch: 28.43ms
150150

151151
An easy approach to follow is that if two blocks of code do the same operation, the one that contains less Python is probably faster. This won't apply if you're using 3rd party packages written purely in Python though.
152152

153-
::::::::::::::::::::::::::::::::::::: callout
154-
155-
### Python bytecode
156-
157-
158-
You can use `dis` to view the bytecode generated by Python, the amount of byte-code more strongly correlates with how much code is being executed by the Python interpreter. However, this still does not account for whether functions called are implemented using Python or C.
159-
160-
The pure Python search compiles to 82 lines of byte-code.
161-
162-
```python
163-
import dis
164-
165-
def manualSearch():
166-
ls = generateInputs()
167-
ct = 0
168-
for i in range(0, int(N*M), M):
169-
for j in range(0, len(ls)):
170-
if ls[j] == i:
171-
ct += 1
172-
break
173-
174-
dis.dis(manualSearch)
175-
```
176-
```output
177-
11 0 LOAD_GLOBAL 0 (generateInputs)
178-
2 CALL_FUNCTION 0
179-
4 STORE_FAST 0 (ls)
180-
181-
12 6 LOAD_CONST 1 (0)
182-
8 STORE_FAST 1 (ct)
183-
184-
13 10 LOAD_GLOBAL 1 (range)
185-
12 LOAD_CONST 1 (0)
186-
14 LOAD_GLOBAL 2 (int)
187-
16 LOAD_GLOBAL 3 (N)
188-
18 LOAD_GLOBAL 4 (M)
189-
20 BINARY_MULTIPLY
190-
22 CALL_FUNCTION 1
191-
24 LOAD_GLOBAL 4 (M)
192-
26 CALL_FUNCTION 3
193-
28 GET_ITER
194-
>> 30 FOR_ITER 24 (to 80)
195-
32 STORE_FAST 2 (i)
196-
197-
14 34 LOAD_GLOBAL 1 (range)
198-
36 LOAD_CONST 1 (0)
199-
38 LOAD_GLOBAL 5 (len)
200-
40 LOAD_FAST 0 (ls)
201-
42 CALL_FUNCTION 1
202-
44 CALL_FUNCTION 2
203-
46 GET_ITER
204-
>> 48 FOR_ITER 14 (to 78)
205-
50 STORE_FAST 3 (j)
206-
207-
15 52 LOAD_FAST 0 (ls)
208-
54 LOAD_FAST 3 (j)
209-
56 BINARY_SUBSCR
210-
58 LOAD_FAST 2 (i)
211-
60 COMPARE_OP 2 (==)
212-
62 POP_JUMP_IF_FALSE 38 (to 76)
213-
214-
16 64 LOAD_FAST 1 (ct)
215-
66 LOAD_CONST 2 (1)
216-
68 INPLACE_ADD
217-
70 STORE_FAST 1 (ct)
218-
219-
17 72 POP_TOP
220-
74 JUMP_FORWARD 1 (to 78)
221-
222-
15 >> 76 JUMP_ABSOLUTE 24 (to 48)
223-
>> 78 JUMP_ABSOLUTE 15 (to 30)
224-
225-
13 >> 80 LOAD_CONST 0 (None)
226-
82 RETURN_VALUE
227-
```
228-
229-
Whereas the `in` variant only compiles to 54.
230-
231-
```python
232-
import dis
233-
234-
def operatorSearch():
235-
ls = generateInputs()
236-
ct = 0
237-
for i in range(0, int(N*M), M):
238-
if i in ls:
239-
ct += 1
240-
241-
dis.dis(operatorSearch)
242-
```
243-
```output
244-
4 0 LOAD_GLOBAL 0 (generateInputs)
245-
2 CALL_FUNCTION 0
246-
4 STORE_FAST 0 (ls)
247-
248-
5 6 LOAD_CONST 1 (0)
249-
8 STORE_FAST 1 (ct)
250-
251-
6 10 LOAD_GLOBAL 1 (range)
252-
12 LOAD_CONST 1 (0)
253-
14 LOAD_GLOBAL 2 (int)
254-
16 LOAD_GLOBAL 3 (N)
255-
18 LOAD_GLOBAL 4 (M)
256-
20 BINARY_MULTIPLY
257-
22 CALL_FUNCTION 1
258-
24 LOAD_GLOBAL 4 (M)
259-
26 CALL_FUNCTION 3
260-
28 GET_ITER
261-
>> 30 FOR_ITER 10 (to 52)
262-
32 STORE_FAST 2 (i)
263-
264-
7 34 LOAD_FAST 2 (i)
265-
36 LOAD_FAST 0 (ls)
266-
38 CONTAINS_OP 0
267-
40 POP_JUMP_IF_FALSE 25 (to 50)
268-
269-
8 42 LOAD_FAST 1 (ct)
270-
44 LOAD_CONST 2 (1)
271-
46 INPLACE_ADD
272-
48 STORE_FAST 1 (ct)
273-
>> 50 JUMP_ABSOLUTE 15 (to 30)
274-
275-
6 >> 52 LOAD_CONST 0 (None)
276-
54 RETURN_VALUE
277-
```
278-
279-
:::::::::::::::::::::::::::::::::::::::::::::
280-
281153

282154
## Example: Parsing data from a text file
283155

learners/technical-appendix.md

Lines changed: 123 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,132 @@ The topics covered here exceed the level of knowledge required to benefit from t
66

77
**Contents**
88

9-
- []()
9+
- [Viewing Python's ByteCode](#viewing-pythons-bytecode)
1010
- []()
1111
- []()
1212

13-
##
13+
## Viewing Python's ByteCode
14+
15+
You can use `dis` to view the bytecode generated by Python, the amount of bytecode more strongly correlates with how much code is being executed by the Python interpreter and hence how long it may take to execute. However, this is a crude proxy as it does not account for whether functions that are called and whether those functions are implemented using Python or C.
16+
17+
The pure Python search compiles to 82 lines of byte-code.
18+
19+
```python
20+
import dis
21+
22+
def manualSearch():
23+
ls = generateInputs()
24+
ct = 0
25+
for i in range(0, int(N*M), M):
26+
for j in range(0, len(ls)):
27+
if ls[j] == i:
28+
ct += 1
29+
break
30+
31+
dis.dis(manualSearch)
32+
```
33+
```output
34+
11 0 LOAD_GLOBAL 0 (generateInputs)
35+
2 CALL_FUNCTION 0
36+
4 STORE_FAST 0 (ls)
37+
38+
12 6 LOAD_CONST 1 (0)
39+
8 STORE_FAST 1 (ct)
40+
41+
13 10 LOAD_GLOBAL 1 (range)
42+
12 LOAD_CONST 1 (0)
43+
14 LOAD_GLOBAL 2 (int)
44+
16 LOAD_GLOBAL 3 (N)
45+
18 LOAD_GLOBAL 4 (M)
46+
20 BINARY_MULTIPLY
47+
22 CALL_FUNCTION 1
48+
24 LOAD_GLOBAL 4 (M)
49+
26 CALL_FUNCTION 3
50+
28 GET_ITER
51+
>> 30 FOR_ITER 24 (to 80)
52+
32 STORE_FAST 2 (i)
53+
54+
14 34 LOAD_GLOBAL 1 (range)
55+
36 LOAD_CONST 1 (0)
56+
38 LOAD_GLOBAL 5 (len)
57+
40 LOAD_FAST 0 (ls)
58+
42 CALL_FUNCTION 1
59+
44 CALL_FUNCTION 2
60+
46 GET_ITER
61+
>> 48 FOR_ITER 14 (to 78)
62+
50 STORE_FAST 3 (j)
63+
64+
15 52 LOAD_FAST 0 (ls)
65+
54 LOAD_FAST 3 (j)
66+
56 BINARY_SUBSCR
67+
58 LOAD_FAST 2 (i)
68+
60 COMPARE_OP 2 (==)
69+
62 POP_JUMP_IF_FALSE 38 (to 76)
70+
71+
16 64 LOAD_FAST 1 (ct)
72+
66 LOAD_CONST 2 (1)
73+
68 INPLACE_ADD
74+
70 STORE_FAST 1 (ct)
75+
76+
17 72 POP_TOP
77+
74 JUMP_FORWARD 1 (to 78)
78+
79+
15 >> 76 JUMP_ABSOLUTE 24 (to 48)
80+
>> 78 JUMP_ABSOLUTE 15 (to 30)
81+
82+
13 >> 80 LOAD_CONST 0 (None)
83+
82 RETURN_VALUE
84+
```
85+
86+
Whereas the `in` variant only compiles to 54.
87+
88+
```python
89+
import dis
90+
91+
def operatorSearch():
92+
ls = generateInputs()
93+
ct = 0
94+
for i in range(0, int(N*M), M):
95+
if i in ls:
96+
ct += 1
97+
98+
dis.dis(operatorSearch)
99+
```
100+
```output
101+
4 0 LOAD_GLOBAL 0 (generateInputs)
102+
2 CALL_FUNCTION 0
103+
4 STORE_FAST 0 (ls)
104+
105+
5 6 LOAD_CONST 1 (0)
106+
8 STORE_FAST 1 (ct)
107+
108+
6 10 LOAD_GLOBAL 1 (range)
109+
12 LOAD_CONST 1 (0)
110+
14 LOAD_GLOBAL 2 (int)
111+
16 LOAD_GLOBAL 3 (N)
112+
18 LOAD_GLOBAL 4 (M)
113+
20 BINARY_MULTIPLY
114+
22 CALL_FUNCTION 1
115+
24 LOAD_GLOBAL 4 (M)
116+
26 CALL_FUNCTION 3
117+
28 GET_ITER
118+
>> 30 FOR_ITER 10 (to 52)
119+
32 STORE_FAST 2 (i)
120+
121+
7 34 LOAD_FAST 2 (i)
122+
36 LOAD_FAST 0 (ls)
123+
38 CONTAINS_OP 0
124+
40 POP_JUMP_IF_FALSE 25 (to 50)
125+
126+
8 42 LOAD_FAST 1 (ct)
127+
44 LOAD_CONST 2 (1)
128+
46 INPLACE_ADD
129+
48 STORE_FAST 1 (ct)
130+
>> 50 JUMP_ABSOLUTE 15 (to 30)
131+
132+
6 >> 52 LOAD_CONST 0 (None)
133+
54 RETURN_VALUE
134+
```
14135

15136
##
16137

0 commit comments

Comments
 (0)