136

I mostly use lambda functions but sometimes use nested functions that seem to provide the same behavior.

Here are some trivial examples where they functionally do the same thing if either were found within another function:

Lambda function

>>> a = lambda x : 1 + x
>>> a(5)
6

Nested function

>>> def b(x): return 1 + x

>>> b(5)
6

Are there advantages to using one over the other? (Performance? Readability? Limitations? Consistency? etc.)

Does it even matter? If it doesn't then does that violate the Pythonic principle:

There should be one-- and preferably only one --obvious way to do it..

0 _
  • 10,524
  • 11
  • 77
  • 109
Ray
  • 187,153
  • 97
  • 222
  • 204

16 Answers16

144

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.

nosklo
  • 217,122
  • 57
  • 293
  • 297
  • 28
    I agree with the answer for when to use `lambda`, but I disagree that this is "very rare", it is common for key functions to `sorted` or `itertools.groupby` etc., e.g. `sorted(['a1', 'b0'], key= lambda x: int(x[1]))` – Chris_Rands Apr 09 '18 at 12:09
  • 1
    I've seen "lambda: " added to some values being passed to methods in Django in order to defer their execution. Is that a legit use case, or is there a better way? (I'm still confused how it all works under the hood.) – odigity Jun 21 '22 at 13:26
38

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.

Thomas Vander Stichele
  • 36,043
  • 14
  • 56
  • 60
30

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 :)

Russia Must Remove Putin
  • 374,368
  • 89
  • 403
  • 331
Chris Lawlor
  • 47,306
  • 11
  • 48
  • 68
  • 25
    Do note that the interview is rather old, and Python has long since added nested scopes, which makes the argument he gives against lambda no longer relevant. I'm sure he still regrets lambda, but not enough to remove it in Python 3.0. – Thomas Wouters Sep 25 '08 at 17:52
  • 14
    Really your example should be an argument against one-liners, not lambdas. Also, you should have used the built-in sum function instead of reducing with a lambda: str(sum(map(lambda x:x**x, range(1001))))[:-10] – Kenan Banks Jun 17 '09 at 00:20
  • 2
    @ThomasWouters: I understand that `lambda` not being removed in 3.0 was a near thing, and that Guido was not fighting to keep it. – Ethan Furman Apr 24 '14 at 01:25
14

More preferable: lambda functions or nested functions (def)?

There is one advantage to using a lambda over a regular function: they are created in an expression.

There are several drawbacks:

  • no name (just '<lambda>')
  • no docstrings
  • no annotations
  • no complex statements

They are also both the same type of object. For those reasons, I generally prefer to create functions with the def keyword instead of with lambdas.

First point - they're the same type of object

A lambda results in the same type of object as a regular function

>>> l = lambda: 0
>>> type(l)
<class 'function'>
>>> def foo(): return 0
... 
>>> type(foo)
<class 'function'>
>>> type(foo) is type(l)
True

Since lambdas are functions, they're first-class objects.

Both lambdas and functions:

  • can be passed around as an argument (same as a regular function)
  • when created within an outer function become a closure over that outer functions' locals

But lambdas are, by default, missing some things that functions get via full function definition syntax.

A lamba's __name__ is '<lambda>'

Lambdas are anonymous functions, after all, so they don't know their own name.

>>> l.__name__
'<lambda>'
>>> foo.__name__
'foo'

Thus lambda's can't be looked up programmatically in their namespace.

This limits certain things. For example, foo can be looked up with serialized code, while l cannot:

>>> import pickle
>>> pickle.loads(pickle.dumps(l))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
_pickle.PicklingError: Can't pickle <function <lambda> at 0x7fbbc0464e18>: 
attribute lookup <lambda> on __main__ failed

We can lookup foo just fine - because it knows its own name:

>>> pickle.loads(pickle.dumps(foo))
<function foo at 0x7fbbbee79268>

Lambdas have no annotations and no docstring

Basically, lambdas are not documented. Let's rewrite foo to be better documented:

def foo() -> int:
    """a nullary function, returns 0 every time"""
    return 0

Now, foo has documentation:

>>> foo.__annotations__
{'return': <class 'int'>}
>>> help(foo)
Help on function foo in module __main__:

foo() -> int
    a nullary function, returns 0 every time

Whereas, we don't have the same mechanism to give the same information to lambdas:

>>> help(l)
Help on function <lambda> in module __main__:

<lambda> lambda (...)

But we can hack them on:

>>> l.__doc__ = 'nullary -> 0'
>>> l.__annotations__ = {'return': int}
>>> help(l)
Help on function <lambda> in module __main__:

<lambda> lambda ) -> in
    nullary -> 0

But there's probably some error messing up the output of help, though.

Lambdas can only return an expression

Lambdas can't return complex statements, only expressions.

>>> lambda: if True: 0
  File "<stdin>", line 1
    lambda: if True: 0
             ^
SyntaxError: invalid syntax

Expressions can admittedly be rather complex, and if you try very hard you can probably accomplish the same with a lambda, but the added complexity is more of a detriment to writing clear code.

We use Python for clarity and maintainability. Overuse of lambdas can work against that.

The only upside for lambdas: can be created in a single expression

This is the only possible upside. Since you can create a lambda with an expression, you can create it inside of a function call.

Creating a function inside a function call avoids the (inexpensive) name lookup versus one created elsewhere.

However, since Python is strictly evaluated, there is no other performance gain to doing so aside from avoiding the name lookup.

For a very simple expression, I might choose a lambda.

I also tend to use lambdas when doing interactive Python, to avoid multiple lines when one will do. I use the following sort of code format when I want to pass in an argument to a constructor when calling timeit.repeat:

import timeit

def return_nullary_lambda(return_value=0):
    return lambda: return_value

def return_nullary_function(return_value=0):
    def nullary_fn():
        return return_value
    return nullary_fn

And now:

>>> min(timeit.repeat(lambda: return_nullary_lambda(1)))
0.24312214995734394
>>> min(timeit.repeat(lambda: return_nullary_function(1)))
0.24894469301216304

I believe the slight time difference above can be attributed to the name lookup in return_nullary_function - note that it is very negligible.

Conclusion

Lambdas are good for informal situations where you want to minimize lines of code in favor of making a singular point.

Lambdas are bad for more formal situations where you need clarity for editors of code who will come later, especially in cases where they are non-trivial.

We know we are supposed to give our objects good names. How can we do so when the object has no name?

For all of these reasons, I generally prefer to create functions with def instead of with lambda.

Russia Must Remove Putin
  • 374,368
  • 89
  • 403
  • 331
12

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
Andy Hayden
  • 359,921
  • 101
  • 625
  • 535
  • 5
    Interesting to see that the lambda and defined versions are roughly equivalent. The last test took more time because python probably needed to allocate space every time it defined that lambda function. – hlin117 Nov 21 '14 at 06:19
  • I guess this makes sense as the definition may reference local variables (which may have changed)... although in the case where it doesn't, like here, cpython could do a better job. – Andy Hayden Nov 21 '14 at 17:24
  • 1
    Use dis.dis; Your (lambda x, y: x * y) create the function every loop. If you create the lambda prior to the loop (aka f = lambda x, y: x * y), the bytecode for calling the function will be the exact same as g/f in your previous example, therefore the lambda performance is the same as a def function. So lambda or def as no impact if you use it the same. Do the inverse, declare the f() function within the loop, then call it... – tito Dec 27 '17 at 16:19
  • @tito I believe that's precisely what the 3 timed examples demonstrate... – Andy Hayden Dec 28 '17 at 06:45
  • @tito oh, you're saying defining the function in the loop, sure, but I would argue that's an unusual pattern. Not sure why this needed the downvote on that comment... – Andy Hayden Dec 28 '17 at 06:50
8

Performance:

Creating a function with lambda is slightly faster than creating it with def. The difference is due to def creating a name entry in the locals table. The resulting function has the same execution speed.


Readability:

Lambda functions are somewhat less readable for most Python users, but also much more concise in some circumstances. Consider converting from using non-functional to functional routine:

# Using non-functional version.

heading(math.sqrt(v.x * v.x + v.y * v.y), math.atan(v.y / v.x))

# Using lambda with functional version.

fheading(v, lambda v: math.sqrt(v.x * v.x + v.y * v.y), lambda v: math.atan(v.y / v.x))

# Using def with functional version.

def size(v):
    return math.sqrt(v.x * v.x + v.y * v.y)

def direction(v):
    return math.atan(v.y / v.x)

deal_with_headings(v, size, direction)

As you can see, the lambda version is shorter and "easier" in the sense that you only need to add lambda v: to the original non-functional version to convert to the functional version. It's also a lot more concise. But remember, a lot of Python users will be confused by the lambda syntax, so what you lose in length and real complexity might be gained back in confusion from fellow coders.


Limitations:

  • lambda functions can only be used once, unless assigned to a variable name.
  • lambda functions assigned to variable names have no advantage over def functions.
  • lambda functions can be difficult or impossible to pickle.
  • def functions' names must be carefully chosen to be reasonably descriptive and unique or at least otherwise unused in scope.

Consistency:

Python mostly avoids functional programming conventions in favor of procedural and simpler objective semantics. The lambda operator stands in direct contrast to this bias. Moreover, as an alternative to the already prevalent def, the lambda function adds diversity to your syntax. Some would consider that less consistent.


Pre-existing functions:

As noted by others, many uses of lambda in the field can be replaced by members of the operator or other modules. For instance:

do_something(x, y, lambda x, y: x + y)
do_something(x, y, operator.add)

Using the pre-existing function can make code more readable in many cases.


The Pythonic principle: “There should be one—and preferably only one—obvious way to do it”

That's similar to the single source of truth doctrine. Unfortunately, the single-obvious-way-to-do-it principle has always been more an wistful aspiration for Python, rather than a true guiding principal. Consider the very-powerful array comprehensions in Python. They are functionally equivalent to the map and filter functions:

[e for e in some_array if some_condition(e)]
filter(some_array, some_condition)

lambda and def are the same.

It's a matter of opinion, but I would say that anything in the Python language intended for general use which doesn't obviously break anything is "Pythonic" enough.

Pi Marillion
  • 4,465
  • 1
  • 19
  • 20
6

I agree with nosklo's advice: if you need to give the function a name, use def. I reserve lambda functions for cases where I'm just passing a brief snippet of code to another function, e.g.:

a = [ (1,2), (3,4), (5,6) ]
b = map( lambda x: x[0]+x[1], a )
Dan Lenski
  • 76,929
  • 13
  • 76
  • 124
  • 3
    In most combinations of map/lambda, you can replace it with a list comprehension or more appropriate function. For example, "map (sum, a)" or "[x[0] + x[1] for x in a]" – John Millikin Sep 25 '08 at 19:16
  • Yes, that's true. Sometimes I prefer map() though. This was mostly just a contrived example of using an in-line function. – Dan Lenski Sep 25 '08 at 20:22
  • exactly... Most examples are contrived, because it is unnatural to use and there are practical better ways in most cases. – nosklo Sep 28 '18 at 19:26
6

While agreeing with the other answers, sometimes it's more readable. Here's an example where lambda comes in handy, in a use case I keep encountering of an N dimensional defaultdict.
Here's an example:

from collections import defaultdict
d = defaultdict(lambda: defaultdict(list))
d['Foo']['Bar'].append(something)

I find it more readable than creating a def for the second dimension. This is even more significant for higher dimensions.

Jonathan Livni
  • 101,334
  • 104
  • 266
  • 359
  • `from functools import partial; defaultdict(partial(defaultdict, list))`. Assign the partial to a name if you want to use it more than once. But, if you *keep* on encountering this construct, it means you aren't DRY. Factor it into a utility library. You can use this construct to create an arbitary n-dimensional defaultdict using other functools (or a loop or recursion). – DylanYoung Mar 15 '19 at 17:12
3

An important limitation of lambdas is that they cannot contain anything besides an expression. It's nearly impossible for a lambda expression to produce anything besides trivial side effects, since it cannot have anywhere near as rich a body as a def'ed function.

That being said, Lua influenced my programming style toward the extensive use of anonymous functions, and I litter my code with them. On top of that, I tend to think about map/reduce as abstract operators in ways I don't consider list comprehensions or generators, almost as If I'm deferring an implementation decision explicitly by using those operators.

Edit: This is a pretty old question, and my opinions on the matter have changed, somewhat.

First off, I am strongly biased against assigning a lambda expression to a variable; as python has a special syntax just for that (hint, def). In addition to that, many of the uses for lambda, even when they don't get a name, have predefined (and more efficient) implementations. For instance, the example in question can be abbreviated to just (1).__add__, without the need to wrap it in a lambda or def. Many other common uses can be satisfied with some combination of the operator, itertools and functools modules.

SingleNegationElimination
  • 151,563
  • 33
  • 264
  • 304
  • 1
    `(1).__add__` -- calling dunder methods directly should almost never happen. A thousand `lambda`s for each direct dunder call. – Ethan Furman Apr 24 '14 at 01:28
  • 1
    @EthanFurman: Well, in my experience, calls of the nature `(1).__add__` are somewhat uncommon, but I would not go anywhere close to "should". without a doubt, I find the former to be vastly more readable to `lambda x: 1 + x`. If we had something more akin to haskells slice notation, `(1+)` that'd be great, but we have to make do with what is semantically exactly that thing, the dunder method name. – SingleNegationElimination Apr 24 '14 at 02:39
3

The primary use of lambda has always been for simple callback functions, and for map, reduce, filter, which require a function as an argument. With list comprehensions becoming the norm, and the added allowed if as in:

x = [f for f in range(1, 40) if f % 2]

it's hard to imagine a real case for the use of lambda in daily use. As a result, I'd say, avoid lambda and create nested functions.

apg
  • 2,611
  • 1
  • 18
  • 19
2

If you are just going to assign the lambda to a variable in the local scope, you may as well use def because it is more readable and can be expanded more easily in the future:

fun = lambda a, b: a ** b # a pointless use of lambda
map(fun, someList)

or

def fun(a, b): return a ** b # more readable
map(fun, someList)
too much php
  • 88,666
  • 34
  • 128
  • 138
  • Both `from operator import pow;map(pow, someList)` and `(a**b for a,b in someList)` are even more readable. – InQβ Aug 17 '17 at 04:23
2
  • Computation time.
  • Function without name.
  • To achieve One function and many use functionality.

Considering a simple example,

# CREATE ONE FUNCTION AND USE IT TO PERFORM MANY OPERATIONS ON SAME TYPE OF DATA STRUCTURE.
def variousUse(a,b=lambda x:x[0]):
    return [b(i) for i in a]

dummyList = [(0,1,2,3),(4,5,6,7),(78,45,23,43)]
variousUse(dummyList)                           # extract first element
variousUse(dummyList,lambda x:[x[0],x[2],x[3]]) # extract specific indexed element
variousUse(dummyList,lambda x:x[0]+x[2])        # add specific elements
variousUse(dummyList,lambda x:x[0]*x[2])        # multiply specific elements
bhargav patel
  • 919
  • 10
  • 16
1

One use for lambdas I have found... is in debug messages.

Since lambdas can be lazily evaluated you can have code like this:

log.debug(lambda: "this is my message: %r" % (some_data,))

instead of possibly expensive:

log.debug("this is my message: %r" % (some_data,))

which processes the format string even if the debug call does not produce output because of current logging level.

Of course for it to work as described the logging module in use must support lambdas as "lazy parameters" (as my logging module does).

The same idea may be applied to any other case of lazy evaluation for on demand content value creation.

For example this custom ternary operator:

def mif(condition, when_true, when_false):
    if condition:
         return when_true()
    else:
         return when_false()

mif(a < b, lambda: a + a, lambda: b + b)

instead of:

def mif(condition, when_true, when_false):
    if condition:
         return when_true
    else:
         return when_false

mif(a < b, a + a, b + b)

with lambdas only the expression selected by the condition will be evaluated, without lambdas both will be evaluated.

Of course you could simply use functions instead of lambdas, but for short expressions lambdas are (c)leaner.

Glushiator
  • 630
  • 8
  • 8
  • 1
    NB `logging` already has lazy formatting: `log.debug("this is my message: %r", some_data)` will only format when/if the message is requested. – j08lue Mar 27 '19 at 14:56
  • @j08lue lambda method skips evaluation of everything in case the debug output is not produced, in the case you show `some_data` could be an expensive expression or function/method call. – Glushiator Jun 26 '19 at 21:38
0

I agree with nosklo. By the way, even with a use once, throw away function, most of the time you just want to use something from the operator module.

E.G :

You have a function with this signature : myFunction(data, callback function).

You want to pass a function that add 2 elements.

Using lambda :

myFunction(data, (lambda x, y : x + y))

The pythonic way :

import operator
myFunction(data, operator.add)

Or course this is a simple example, but there is a lot of stuff the operator module provides, including the items setters / getters for list and dict. Really cool.

Bite code
  • 578,959
  • 113
  • 301
  • 329
0

A major difference is that you can not use def functions inline, which is in my opinion the most convenient use case for a lambda function. For example when sorting a list of objects:

my_list.sort(key=lambda o: o.x)

I would therefore suggest keeping the use of lambdas to this kind of trivial operations, which also do not really benefit from the automatic documentation provided by naming the function.

Ali Rasim Kocal
  • 528
  • 3
  • 14
-2

lambda is useful for generating new functions:

>>> def somefunc(x): return lambda y: x+y
>>> f = somefunc(10)
>>> f(2)
12
>>> f(4)
14
scrpy
  • 985
  • 6
  • 23