Which is more preferable to use: lambda functions or nested functions ('def')?

If you need to assign the lambda to a name, use a def instead. defs are just syntactic sugar for an assignment, so the result is the same, and they are a lot more flexible and readable.

lambdas can be used for use once, throw away functions which won't have a name.

However, this use case is very rare. You rarely need to pass around unnamed function objects.

The builtins map() and filter() need function objects, but list comprehensions and generator expressions are generally more readable than those functions and can cover all use cases, without the need of lambdas.

For the cases you really need a small function object, you should use the operator module functions, like operator.add instead of lambda x, y: x + y

If you still need some lambda not covered, you might consider writing a def, just to be more readable. If the function is more complex than the ones at operator module, a def is probably better.

So, real world good lambda use cases are very rare.


Practically speaking, to me there are two differences:

The first is about what they do and what they return:

  • def is a keyword that doesn't return anything and creates a 'name' in the local namespace.

  • lambda is a keyword that returns a function object and does not create a 'name' in the local namespace.

Hence, if you need to call a function that takes a function object, the only way to do that in one line of python code is with a lambda. There's no equivalent with def.

In some frameworks this is actually quite common; for example, I use Twisted a lot, and so doing something like

d.addCallback(lambda result: setattr(self, _someVariable, result))

is quite common, and more concise with lambdas.

The second difference is about what the actual function is allowed to do.

  • A function defined with 'def' can contain any python code
  • A function defined with 'lambda' has to evaluate to an expression, and can thus not contain statements like print, import, raise, ...

For example,

def p(x): print x

works as expected, while

lambda x: print x

is a SyntaxError.

Of course, there are workarounds - substitute print with sys.stdout.write, or import with __import__. But usually you're better off going with a function in that case.


In this interview, Guido van Rossum says he wishes he hadn't let 'lambda' into Python:

"Q. What feature of Python are you least pleased with?

Sometimes I've been too quick in accepting contributions, and later realized that it was a mistake. One example would be some of the functional programming features, such as lambda functions. lambda is a keyword that lets you create a small anonymous function; built-in functions such as map, filter, and reduce run a function over a sequence type, such as a list.

In practice, it didn't turn out that well. Python only has two scopes: local and global. This makes writing lambda functions painful, because you often want to access variables in the scope where the lambda was defined, but you can't because of the two scopes. There's a way around this, but it's something of a kludge. Often it seems much easier in Python to just use a for loop instead of messing around with lambda functions. map and friends work well only when there's already a built-in function that does what you want.

IMHO, Iambdas can be convenient sometimes, but usually are convenient at the expense of readibility. Can you tell me what this does:

str(reduce(lambda x,y:x+y,map(lambda x:x**x,range(1,1001))))[-10:]

I wrote it, and it took me a minute to figure it out. This is from Project Euler - i won't say which problem because i hate spoilers, but it runs in 0.124 seconds :)


For n=1000 here's some timeit's of calling a function vs a lambda:

In [11]: def f(a, b):
             return a * b

In [12]: g = lambda x, y: x * y

In [13]: %%timeit -n 100
for a in xrange(n):
  for b in xrange(n):
    f(a, b)
   ....:
100 loops, best of 3: 285 ms per loop

In [14]: %%timeit -n 100
for a in xrange(n):
  for b in xrange(n):
    g(a, b)
   ....:
100 loops, best of 3: 298 ms per loop

In [15]: %%timeit -n 100
for a in xrange(n):
  for b in xrange(n):
    (lambda x, y: x * y)(a, b)
   ....:
100 loops, best of 3: 462 ms per loop