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

PythonSyntaxFunctionLambda

Python Problem Overview


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..

Python Solutions


Solution 1 - Python

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.

Solution 2 - Python

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.

Solution 3 - Python

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

Solution 4 - Python

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

Solution 5 - Python

> ## 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.

Solution 6 - Python

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.

Solution 7 - Python

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 )

Solution 8 - Python

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.

Solution 9 - Python

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.

Solution 10 - Python

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.

Solution 11 - Python

  • 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

Solution 12 - Python

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)

Solution 13 - Python

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.

Solution 14 - Python

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.

Solution 15 - Python

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.

Solution 16 - Python

lambda is useful for generating new functions:

>>> def somefunc(x): return lambda y: x+y
>>> f = somefunc(10)
>>> f(2)
12
>>> f(4)
14

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRayView Question on Stackoverflow
Solution 1 - PythonnoskloView Answer on Stackoverflow
Solution 2 - PythonThomas Vander SticheleView Answer on Stackoverflow
Solution 3 - PythonChris LawlorView Answer on Stackoverflow
Solution 4 - PythonAndy HaydenView Answer on Stackoverflow
Solution 5 - PythonRussia Must Remove PutinView Answer on Stackoverflow
Solution 6 - PythonPi MarillionView Answer on Stackoverflow
Solution 7 - PythonDan LenskiView Answer on Stackoverflow
Solution 8 - PythonJonathan LivniView Answer on Stackoverflow
Solution 9 - PythonapgView Answer on Stackoverflow
Solution 10 - PythonSingleNegationEliminationView Answer on Stackoverflow
Solution 11 - Pythonbhargav patelView Answer on Stackoverflow
Solution 12 - Pythontoo much phpView Answer on Stackoverflow
Solution 13 - PythonGlushiatorView Answer on Stackoverflow
Solution 14 - Pythone-satisView Answer on Stackoverflow
Solution 15 - PythonAli Rasim KocalView Answer on Stackoverflow
Solution 16 - PythonNussView Answer on Stackoverflow