1
lst = [randint(0,i) for i in range(0,1000)]
start = time.time()
lst = [item*item for item in lst]
end = time.time()
print('%.7f' %(start - end))

f = lambda x: x**2

lst = [randint(0,i) for i in range(0,1000)]
start = time.time()
lst = [f(item) for item in lst]
end = time.time()
print('%.7f' %(start - end))

The time for inline calculation ranges from 0.0000665 to 0.0000813. Whereas that for lambda is somewhere in the range 0.0004215 to 0.0004265. Why is there such a huge difference in time?

djokester
  • 567
  • 9
  • 20
  • the two cases are not comparable, in the first case you're simply iterating over a list raising items to power 2, in the second case you're call the lambda function passing it the variable doing the calculation then returning the item, of-course function calls take much longer than multiplication – sgDysregulation Jul 29 '17 at 16:56
  • The calling takes that much of time? – djokester Jul 29 '17 at 16:57
  • `x**2` works different than `x*x`... – Willem Van Onsem Jul 29 '17 at 16:59
  • A function call means a jump to different place in memory,intialising the local variables, etc.. – sgDysregulation Jul 29 '17 at 16:59
  • @Djokester Yes. When you make a function call, Python calls several other methods on the function object behind the scenes. It must also create a new frame for the function call. All of these things take more time than simply doing `x*x`. – Christian Dean Jul 29 '17 at 17:00

1 Answers1

4

I can see 2 possible reasons:

  1. item * item yields the same result as item ** 2, but you're making an assumption about implementation of ** operator. Still, more important reason is...
  2. lambda is really a function - it has the same closure as a function you'd declare with def in the same scope, and in the same way as such function, it will get it's own stack frame when executed. Creating, pushing and dropping such frame take time and this is probably what introduces such a big overhead. Quoting from here:

Semantically, they (lambdas) are just syntactic sugar for a normal function definition.

Try benchmarking following calculations:

  • inline item*item
  • inline item **2
  • usage of def foo(x): return x*x
  • usage of def foo(x): return x**2
  • usage of lambda x: x*x
  • usage of lambda x: x**2

and you'll figure out real reasons (please share these results too, I'm sorta interested myself). I'd expect 2 first ways to be similiar in efficiency, and following 4 also similiar to each other, but slower by few orders of magnitude than those inline ones.

Also: use timeit intead of time.time() - it is more reliable. Here's a wider list of possibilities when it comes to measuring time of execution, though I'd really recommend timeit, as it is created exactly for the kind of job that you want to do here.

Filip Malczak
  • 3,124
  • 24
  • 44