Python: why list comprehension is slower than looping

In fact, these are the same functions, except that sum used instead of x=0; x+= to understand the list x=0; x+= x=0; x+= , since a later version is not supported. Why is comprehension of the list about 40% slower?

 #list comprehension def movingAverage(samples, n=3): return [float(sum(samples[ij] for j in range(n)))/n for i in range(n-1, len(samples))] #regular def moving_average(samples, n=3): l =[] for i in range(n-1, len(samples)): x= 0 for j in range(n): x+= samples[ij] l.append((float(x)/n)) return l 

To synchronize the inputs of the sample, I used the variations on [i*random.random() for i in range(x)]

+4
source share
1 answer

You use the generator expression in your understanding of the list:

 sum(samples[ij] for j in range(n)) 

Generator expressions require creating a new frame each time it starts, like a function call. It is relatively expensive.

You do not need to use a generator expression at all; all you need to do is slice the samples list:

 sum(samples[i - n + 1:i + 1]) 

You can specify the second argument, the start value for the sum() function; set 0.0 to get a floating point result:

 sum(samples[i - n + 1:i + 1], 0.0) 

Together, these changes matter:

 >>> from timeit import timeit >>> import random >>> testdata = [i*random.random() for i in range(1000)] >>> def slow_moving_average(samples, n=3): ... return [float(sum(samples[ij] for j in range(n)))/n for i in range(n-1, len(samples))] ... >>> def fast_moving_average(samples, n=3): ... return [sum(samples[i - n + 1:i + 1], 0.0) / n for i in range(n-1, len(samples))] ... >>> def verbose_moving_average(samples, n=3): ... l =[] ... for i in range(n-1, len(samples)): ... x = 0.0 ... for j in range(n): ... x+= samples[ij] ... l.append(x / n) ... return l ... >>> timeit('f(s)', 'from __main__ import verbose_moving_average as f, testdata as s', number=1000) 0.9375386269966839 >>> timeit('f(s)', 'from __main__ import slow_moving_average as f, testdata as s', number=1000) 1.9631599469939829 >>> timeit('f(s)', 'from __main__ import fast_moving_average as f, testdata as s', number=1000) 0.5647804250038462 
+10
source

Source: https://habr.com/ru/post/1276202/


All Articles