If in doubt: measure.
What is better?
- fewer bytecode? ==>
import dis and compare bytecode
- faster execution ==>
import timeit and compare runtimes
- readability ==> depends on your weakest cowororkers ability to grok¹ your code (run a file with
import this² as code ;o)
like so:
import dis
import timeit
def a():
count = 0
p = print # local caching of global lookup - way faster
while count < 10:
p('hello', flush=True)
count += 1
def b():
p = print # local caching of global lookup - way faster
p('hello', flush=True)
p('hello', flush=True)
p('hello', flush=True)
p('hello', flush=True)
p('hello', flush=True)
p('hello', flush=True)
p('hello', flush=True)
p('hello', flush=True)
p('hello', flush=True)
p('hello', flush=True)
def c():
print( *("hello" for _ in range(10)), sep="\n", flush=True)
aa = timeit.timeit(a, number=100)
bb = timeit.timeit(b, number=100)
cc = timeit.timeit(c, number=100)
print(aa, bb, cc, sep="\n")
dis.dis(a)
print("-"*80)
dis.dis(b)
print("-"*80)
dis.dis(c)
to get
0.059448799999699986 # while is faster - who would have thought
0.06415420000030281 # multiple prints
0.06454990000020189 # one print but list comp
# while loop - seems to be shortest
5 0 LOAD_CONST 1 (0)
2 STORE_FAST 0 (count)
6 4 LOAD_GLOBAL 0 (print)
6 STORE_FAST 1 (p)
7 8 LOAD_FAST 0 (count)
10 LOAD_CONST 2 (10)
12 COMPARE_OP 0 (<)
14 POP_JUMP_IF_FALSE 24 (to 48)
8 >> 16 LOAD_FAST 1 (p)
18 LOAD_CONST 3 ('hello')
20 LOAD_CONST 4 (True)
22 LOAD_CONST 5 (('flush',))
24 CALL_FUNCTION_KW 2
26 POP_TOP
9 28 LOAD_FAST 0 (count)
30 LOAD_CONST 6 (1)
32 INPLACE_ADD
34 STORE_FAST 0 (count)
7 36 LOAD_FAST 0 (count)
38 LOAD_CONST 2 (10)
40 COMPARE_OP 0 (<)
42 POP_JUMP_IF_TRUE 8 (to 16)
44 LOAD_CONST 0 (None)
46 RETURN_VALUE
>> 48 LOAD_CONST 0 (None)
50 RETURN_VALUE
--------------------------------------------------------------------------------
# multiple prints
11 0 LOAD_GLOBAL 0 (print)
2 STORE_FAST 0 (p)
12 4 LOAD_FAST 0 (p)
6 LOAD_CONST 1 ('hello')
8 LOAD_CONST 2 (True)
10 LOAD_CONST 3 (('flush',))
12 CALL_FUNCTION_KW 2
14 POP_TOP
13 16 LOAD_FAST 0 (p)
18 LOAD_CONST 1 ('hello')
20 LOAD_CONST 2 (True)
22 LOAD_CONST 3 (('flush',))
24 CALL_FUNCTION_KW 2
26 POP_TOP
14 28 LOAD_FAST 0 (p)
30 LOAD_CONST 1 ('hello')
32 LOAD_CONST 2 (True)
34 LOAD_CONST 3 (('flush',))
36 CALL_FUNCTION_KW 2
38 POP_TOP
15 40 LOAD_FAST 0 (p)
42 LOAD_CONST 1 ('hello')
44 LOAD_CONST 2 (True)
46 LOAD_CONST 3 (('flush',))
48 CALL_FUNCTION_KW 2
50 POP_TOP
16 52 LOAD_FAST 0 (p)
54 LOAD_CONST 1 ('hello')
56 LOAD_CONST 2 (True)
58 LOAD_CONST 3 (('flush',))
60 CALL_FUNCTION_KW 2
62 POP_TOP
17 64 LOAD_FAST 0 (p)
66 LOAD_CONST 1 ('hello')
68 LOAD_CONST 2 (True)
70 LOAD_CONST 3 (('flush',))
72 CALL_FUNCTION_KW 2
74 POP_TOP
18 76 LOAD_FAST 0 (p)
78 LOAD_CONST 1 ('hello')
80 LOAD_CONST 2 (True)
82 LOAD_CONST 3 (('flush',))
84 CALL_FUNCTION_KW 2
86 POP_TOP
19 88 LOAD_FAST 0 (p)
90 LOAD_CONST 1 ('hello')
92 LOAD_CONST 2 (True)
94 LOAD_CONST 3 (('flush',))
96 CALL_FUNCTION_KW 2
98 POP_TOP
20 100 LOAD_FAST 0 (p)
102 LOAD_CONST 1 ('hello')
104 LOAD_CONST 2 (True)
106 LOAD_CONST 3 (('flush',))
108 CALL_FUNCTION_KW 2
110 POP_TOP
21 112 LOAD_FAST 0 (p)
114 LOAD_CONST 1 ('hello')
116 LOAD_CONST 2 (True)
118 LOAD_CONST 3 (('flush',))
120 CALL_FUNCTION_KW 2
122 POP_TOP
124 LOAD_CONST 0 (None)
126 RETURN_VALUE
--------------------------------------------------------------------------------
# fancy generator comprehension
24 0 LOAD_GLOBAL 0 (print)
2 LOAD_CONST 1 (<code object <genexpr> at 0x000002320A8468C0, file "c:\Users\partner\Documents\Coding\python\t.py", line 24>)
4 LOAD_CONST 2 ('c.<locals>.<genexpr>')
6 MAKE_FUNCTION 0
8 LOAD_GLOBAL 1 (range)
10 LOAD_CONST 3 (10)
12 CALL_FUNCTION 1
14 GET_ITER
16 CALL_FUNCTION 1
18 LOAD_CONST 4 ('\n')
20 LOAD_CONST 5 (True)
22 LOAD_CONST 6 (('sep', 'flush'))
24 BUILD_CONST_KEY_MAP 2
26 CALL_FUNCTION_EX 1
28 POP_TOP
30 LOAD_CONST 0 (None)
32 RETURN_VALUE
Disassembly of <code object <genexpr> at 0x000002320A8468C0, file "c:\Users\partner\Documents\Coding\python\t.py", line 24>:
0 GEN_START 0
24 2 LOAD_FAST 0 (.0)
>> 4 FOR_ITER 5 (to 16)
6 STORE_FAST 1 (_)
8 LOAD_CONST 0 ('hello')
10 YIELD_VALUE
12 POP_TOP
14 JUMP_ABSOLUTE 2 (to 4)
>> 16 LOAD_CONST 1 (None)
18 RETURN_VALUE
¹) Coined by Robert A. Heinlein in his science fiction novel Stranger in a Strange Land source.
²) The Zen of Python