13

I think lambda is faster than function call, but after testing, I find out that I am wrong. Function call is definitely faster than lambda call.

Can anybody tell me why?

And how to speed up function call in Python?

I'm using Ubuntu 14.04 and Python 2.7.6

>>> timeit('def a():return 222*333 ;a()')
0.08195090293884277
>>> timeit('a=lambda:222*333 ;a()')
0.11071300506591797

>>> timeit('a=lambda: [].extend(range(10)) ;a()')
0.40241098403930664
>>> timeit('a=lambda: [].extend(range(10)) ;a()')
0.4011270999908447
>>> timeit('a=lambda: [].extend(range(10)) ;a()')
0.4064619541168213
>>> timeit('def a(): return [].extend(range(10)) ;a()')
0.07965493202209473
>>> timeit('def a(): return [].extend(range(10)) ;a()')
0.08039593696594238
>>> timeit('def a(): return [].extend(range(10)) ;a()')
0.08103609085083008
>>> timeit('def a(): return [].extend(range(10)) ;a()')
0.08639097213745117

Sorry for my mistake, there is no difference. Correct testing:

>>> timeit('a()', setup="def a():return 222*333")
0.07061290740966797
>>> timeit('a()', setup="a=lambda: 222*333")
0.06967616081237793

3 Answers 3

17

timeit('def a(): return [].extend(range(10)) ;a()') is not calling a(); The call to a() is part of the definition of a:

In [34]: def a(): return [].extend(range(10)) ;a()

In [35]: import dis

In [36]: dis.dis(a)
  1           0 BUILD_LIST               0
              3 LOAD_ATTR                0 (extend)
              6 LOAD_GLOBAL              1 (range)
              9 LOAD_CONST               1 (10)
             12 CALL_FUNCTION            1
             15 CALL_FUNCTION            1
             18 RETURN_VALUE        
             19 LOAD_GLOBAL              2 (a)
             22 CALL_FUNCTION            0       #<-- a is called
             25 POP_TOP             

If you test the pieces separately, the difference is negligible:

In [24]: %timeit a=lambda: [].extend(range(10))
10000000 loops, best of 3: 68.6 ns per loop

In [25]: %timeit def a2(): return [].extend(range(10))
10000000 loops, best of 3: 68.8 ns per loop

In [22]: %timeit a()
1000000 loops, best of 3: 445 ns per loop

In [23]: %timeit a2()
1000000 loops, best of 3: 442 ns per loop
Sign up to request clarification or add additional context in comments.

1 Comment

Sorry for my stupid mistake... I ran this testing, there is no definitely difference. >>> timeit('a()', setup="def a():return 222*333") 0.07061290740966797 >>> timeit('a()', setup="a=lambda: 222*333") 0.06967616081237793
15

As pointed out above, your first test only profiles the time it takes to define a. It's actually never called.

Lambda expressions and "normal" functions generate the exact same bytecode, as you can see if you use the dis module:

def a(): return 10
b = lambda: 10

import dis

>>> dis.dis(a)
1           0 LOAD_CONST               1 (10)
            3 RETURN_VALUE
>>> dis.dis(b)
1           0 LOAD_CONST               1 (10)
            3 RETURN_VALUE

3 Comments

This is an important point. People sometimes think "lambda functions" are a special kind of thing, but they're not: lambda is simply a keyword used to make a plain old function, mostly handy because it can be used inline. That's it. They don't have magic powers.
@DSM Actually lambdas are equivalent to the more restricted case of a function containing a single return statement. So compiling a lambda might be a little simpler than compiling a function.
@augurar: that's the first time I've ever heard someone suggest that an advantage of lambdas (or any syntactic choice in Python, really) is simpler compilation. Anyway, the point isn't that a lambda can be used to make any function, it's that what the lambda keyword creates is a function, and not a "lambda function".
8

There's no difference in calling a lambda versus a function. A lambda is just a function created with a single expression and no name.

Say we have two identical functions, one created with a function definition, the other with a lambda expression:

def a():
    return 222*333

b = lambda: 222*333

We see that both are the same type of function object and they both share equivalent byte-code:

>>> type(a)
<class 'function'>
>>> type(b)
<class 'function'>

>>> import dis
>>> dis.dis(a)
  2           0 LOAD_CONST               3 (73926)
              2 RETURN_VALUE
>>> dis.dis(b)
  1           0 LOAD_CONST               3 (73926)
              2 RETURN_VALUE

How can you speed that up? You don't. It's Python. It's pre-optimized for you. There's nothing more for you to do with this code.

Perhaps you could give it to another interpreter, or rewrite it in another language, but if you're sticking to Python, there's nothing more to do now.

Timing it

Here's how I would examine the timings.

Timeit's timeit and repeat both take a callable:

import timeit

Note that timeit.repeat takes a repeat argument as well:

>>> min(timeit.repeat(a, repeat=100))
0.06456905393861234
>>> min(timeit.repeat(b, repeat=100))
0.06374448095448315

These differences are too small to be significant.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.