i looking in performance issues of loop structures in python , found following statements:
besides syntactic benefit of list comprehensions, fast or faster equivalent use of map. (performance tips)
list comprehensions run bit faster equivalent for-loops (unless you're going throw away result). (python speed)
i wondering difference under hood gives list comprehension advantage. thanks.
test one: throwing away result.
here's our dummy function:
def examplefunc(x): pass and here our challengers:
def listcomp_throwaway(): [examplefunc(i) in range(100)] def forloop_throwaway(): in range(100): examplefunc(i) i won't analysis of raw speed, why, per op's question. lets take @ diffs of machine code.
--- list comprehension +++ loop @@ -1,15 +1,16 @@ - 55 0 build_list 0 + 59 0 setup_loop 30 (to 33) 3 load_global 0 (range) 6 load_const 1 (100) 9 call_function 1 12 get_iter - >> 13 for_iter 18 (to 34) + >> 13 for_iter 16 (to 32) 16 store_fast 0 (i) - 19 load_global 1 (examplefunc) + + 60 19 load_global 1 (examplefunc) 22 load_fast 0 (i) 25 call_function 1 - 28 list_append 2 - 31 jump_absolute 13 - >> 34 pop_top - 35 load_const 0 (none) - 38 return_value + 28 pop_top + 29 jump_absolute 13 + >> 32 pop_block + >> 33 load_const 0 (none) + 36 return_value the race on. listcomp's first move build empty list, while loop's setup loop. both of them proceed load global range(), constant 100, , call range function generator. both current iterator , next item, , store variable i. load examplefunc , , call examplefunc. listcomp appends list , starts loop on again. loop same in 3 instructions instead of two. both load none , return it.
so seems better in analysis? here, list comprehension redundant operations such building list , appending it, if don't care result. loop pretty efficient too.
if time them, using loop one-third faster list comprehension. (in test, examplefunc divided argument 5 , threw away instead of doing nothing @ all.)
test two: keeping result normal.
no dummy function test. here our challengers:
def listcomp_normal(): l = [i*5 in range(100)] def forloop_normal(): l = [] in range(100): l.append(i*5) the diff isn't use today. it's 2 machine codes in 2 blocks.
list comp's machine code:
55 0 build_list 0 3 load_global 0 (range) 6 load_const 1 (100) 9 call_function 1 12 get_iter >> 13 for_iter 16 (to 32) 16 store_fast 0 (i) 19 load_fast 0 (i) 22 load_const 2 (5) 25 binary_multiply 26 list_append 2 29 jump_absolute 13 >> 32 store_fast 1 (l) 35 load_const 0 (none) 38 return_value for loop's machine code:
59 0 build_list 0 3 store_fast 0 (l) 60 6 setup_loop 37 (to 46) 9 load_global 0 (range) 12 load_const 1 (100) 15 call_function 1 18 get_iter >> 19 for_iter 23 (to 45) 22 store_fast 1 (i) 61 25 load_fast 0 (l) 28 load_attr 1 (append) 31 load_fast 1 (i) 34 load_const 2 (5) 37 binary_multiply 38 call_function 1 41 pop_top 42 jump_absolute 19 >> 45 pop_block >> 46 load_const 0 (none) 49 return_value as can tell, list comprehension has fewer instructions loop does.
list comprehension's checklist:
- build anonymous empty list.
- load
range. - load
100. - call
range. - get iterator.
- get next item on iterator.
- store item onto
i. - load
i. - load integer five.
- multiply times five.
- append list.
- repeat steps 6-10 until range empty.
- point
lanonymous empty list.
for loop's checklist:
- build anonymous empty list.
- point
lanonymous empty list. - setup loop.
- load
range. - load
100. - call
range. - get iterator.
- get next item on iterator.
- store item onto
i. - load list
l. - load attribute
appendon list. - load
i. - load integer five.
- multiply times five.
- call
append. - go top.
- go absolute.
(not including these steps: load none, return it.)
the list comprehension doesn't have these things:
- load append of list every time, since it's pre-bound local variable.
- load
itwice per loop - spend 2 instructions going top
- directly append list instead of calling wrapper appens list
in conclusion, listcomp lot faster if going use values, if don't it's pretty slow.
real speeds
test one: loop faster one-third*
test two: list comprehension faster two-thirds*
*about -> second decimal place acurrate
Comments
Post a Comment