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

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

Here are some trivial examples when they functionally do the same if they were found in 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 any advantages to using one over the other? (Performance? Readability? Limitations? Consistency? Etc.)

Does it matter? If this is not the case, it violates the Python principle:

There should be one โ€” and preferably only one โ€” obvious way to do it .

+92
function python syntax lambda
Sep 25 '08 at 17:15
source share
16 answers

If you need to give lambda name, use def instead. def is just the syntactic sugar for the assignment, so the result is the same and they are much more flexible and readable.

lambda can be used to use once, throw away functions that will not have a name.

However, this use case is very rare. You rarely have to go through unnamed function objects.

The built-in map() and filter() functions need functional objects, but the list and generator expressions are generally more readable than these functions and can cover all use cases, without the need for a lambda.

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

If you still need some kind of lambda that hasn't been closed, you might consider writing def to be more readable. If the function is more complex than those in the operator module, then def is probably better.

Thus, real examples of good use of lambda very rare.

+92
Sep 25 '08 at 17:16
source share

Practically speaking, for me there are two differences:

The first is what they do and what they return:

  • def is a keyword that returns nothing 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.

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

In some frameworks, this is actually quite common; for example, I often use Twisted , and therefore does something like

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

quite common and more concise with lambdas.

The second difference is that it is allowed to do the actual function.

  • A function defined with 'def' can contain any python code
  • A function defined with 'lambda' must evaluate the expression and therefore cannot contain expressions such as print, import, raise, ...

For example,

 def p(x): print x 

works as expected, and

 lambda x: print x 

is the syntax.

Of course, there are workarounds - replace print with sys.stdout.write or import with __import__ . But usually you better go with the function in this case.

+30
Sep 26 '08 at 10:20
source share

Guido van Rossum says in this interview that he would like him to not let the lambda into Python:

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

Sometimes I took deposits too quickly, and then I realized that this was a mistake. One example might be some functional programming functions, such as lambda functions. lambda is a keyword that allows you to create a small anonymous function; built-in functions, such as matching, filtering, and decreasing, run the function on a sequence type, such as a list.

In practice, this turned out to be not so good. Python has only two areas: local and global. This makes writing lambda functions painful because you often need access to variables in the area where the lambda was defined, but you cannot because of these two areas. There is a way around this, but it's a bit of a kluge. It is often much easier in Python to just use a for loop rather than messing with lambda functions. A map and friends work well only when there is already a built-in function that does what you want.

IMHO, sometimes iambdas can be convenient, but usually convenient due to readability. 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 will not say what the problem is, because I hate spoilers, but it works in 0.124 seconds :)

+21
Sep 25 '08 at 17:29
source share

With n = 1000, here is some time of the vs lambda function call:

 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 
+9
Aug 16 '12 at 13:16
source share

I agree with nosklo's advice: if you need to specify a name function, use def . I reserve the lambda functions for cases where I just pass a short piece of code to another function, for example:

 a = [ (1,2), (3,4), (5,6) ] b = map( lambda x: x[0]+x[1], a ) 
+6
Sep 25 '08 at 17:19
source share

Performance:

Creating a function with lambda is a little faster than creating with def . The difference is because def creates a name record in the locals table. The resulting function has the same execution speed.




Resolution:

Lambda functions are somewhat less readable for most Python users, but in some cases also significantly more concise. Consider the transition from using a non-functional to a functional subprogram:

 # Using non-functional version. heading(math.sqrt(vx * vx + vy * vy), math.atan(vy / vx)) # Using lambda with functional version. fheading(v, lambda v: math.sqrt(vx * vx + vy * vy), lambda v: math.atan(vy / vx)) # Using def with functional version. def size(v): return math.sqrt(vx * vx + vy * vy) def direction(v): return math.atan(vy / vx) deal_with_headings(v, size, direction) 

As you can see, the lambda version is shorter and โ€œsimplerโ€ in the sense that you need to add lambda v: to the original non-functional version to convert to a functional version. It is also much more concise. But remember that many Python users will be confused by the lambda syntax, so what you lose in length and real complexity can be recovered confused by other coders.




Limitations:

  • lambda functions can only be used once if a variable name is not assigned.
  • lambda functions assigned to variable names have no advantages over def functions.
  • lambda functions may be difficult or impossible for brine.
  • def function names must be carefully chosen to be descriptive and unique enough, or at least not otherwise used in scope.



Consistency:

Python basically avoids functional programming conventions in favor of procedural and simple objective semantics. The lambda operator is in direct contrast with this offset. Moreover, as an alternative to the existing def , the lambda function adds variety to your syntax. Some find this less consistent.




Pre-existing Features:

As others have noted, many uses of lambda in a field can be replaced with members of operator or other modules. For example:

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

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




Pythons Principle: "There should be one โ€” and preferably only one โ€” the obvious way to do this."

It seems like a doctrine of the only source of truth . Unfortunately, the principle of an unambiguous path to business has always been rather a brooding pursuit of Python, rather than a true managing director. Consider some very powerful array building methods 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 same.

This is a matter of opinion, but I would say that everything in Python intended for general use that clearly does not violate anything is "Pythonic" enough.

+5
Feb 11 '16 at 18:14
source share

Agreeing with the other answers is sometimes more readable. Here's an example where lambda comes in handy; in the use case, I continue to encounter an N-dimensional defaultdict . example:

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

I find it more readable than creating def for the second dimension. This is even more important for higher measurements.

+4
Dec 27 '13 at 10:54 on
source share

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

There is one advantage to using lambdas over a regular function (they are created in an expression) and several disadvantages. For this reason, I prefer to create functions with the def keyword rather than lambdas.

The first point is the same type of object

Lambda leads to 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 

Because lambda expressions are functions, they are first-class objects.

Both lambdas and functions:

  • can be passed as an argument (same as a regular function)
  • when created inside an external function, it becomes a closure over the local elements of this external function

But the default lambdas lack some of the things that functions get through the full function definition syntax.

Lamb __name__ is '<lambda>'

After all, lambdas are anonymous functions, so they donโ€™t know their name.

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

Thus, lambda cannot be found programmatically in their namespace.

This limits certain things. For example, foo can be searched using 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 just find foo - because he knows his name:

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

There are no annotations or documentation lines in lambdas

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

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

Now foo has the 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 do not have the same mechanism for providing the same information to lambdas:

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

But we can hack them into:

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

But perhaps help is displayed due to an error.

Lambdas can only return an expression

Lambda cannot return complex expressions, only expressions.

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

Expressions can be quite complex, and if you try your best, you can probably do the same with lambdas, but the extra complexity is more damaging to writing clear code.

We use Python for clarity and ease of maintenance. Overuse of lambdas may work against this.

The only plus for lambda: can be created in one expression

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

Creating a function inside a function call avoids a (inexpensive) name lookup compared to a function created elsewhere.

However, since Python is strictly evaluated, it offers no other performance gain other than avoiding name lookups.

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

I also tend to use lambdas when working with interactive Python to avoid multiple lines when one will do. I use the following kind of code format when I want to pass an argument to the 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 that the small time difference above can be related to finding a name in return_nullary_function - note that it is very insignificant.

Conclusion

Lambdas are good for informal situations when you want to minimize lines of code in favor of highlighting a special situation.

Lambdas are bad for more formal situations when you need clarity for code editors that come later, especially when they are nontrivial.

We know that we must give our objects good names. How can we do this if the object does not have a name?

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

+4
Mar 27 '18 at 19:03
source share

The main use of lambda has always been for simple callback functions, and for a map, reduce, filter, requiring a function as an argument. Matching lists becomes the norm, and adding is allowed if:

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

Itโ€™s hard to imagine the real case of using lambda in everyday use. As a result, I would say avoid lambda and create nested functions.

+3
Sep 25 '08 at 19:13
source share

An important limitation of lambda is that they cannot contain anything but an expression. For a lambda expression, it is almost impossible to get anything other than trivial side effects, since it cannot have anywhere, like a rich body, like a def 'ed function.

Having said that, Lua influenced my programming style in the widespread use of anonymous functions, and I put my code with them. In addition, I tend to think of map / reduce as abstract operators in ways that I donโ€™t consider when analyzing lists or generators, almost as if I deferred the implementation decision explicitly using these operators.

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

Firstly, I am very prone to assigning a lambda variable to a variable; since python has a special syntax just for that (hint, def ). In addition to this, many of the uses of lambda, even if they do not get a name, have predefined (and more efficient) implementations. For example, the example in question can be shortened to (1).__add__ , without having to wrap it in lambda or def . Many other common applications can be satisfied with some combination of operator , itertools and functools .

+3
Jun 17 '09 at 0:02
source share
  • Computation time.
  • Function without a name.
  • To achieve one function, many use functionality.

Looking at 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 
+2
Jul 26 '18 at 10:43
source share

If you are just going to assign a lambda to a variable in the local scope, you can also use def because it is more readable and may be more easily expanded 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) 
+1
Nov 18. '08 at 7:19
source share

One use for lambdas that I found ... is in debugging 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 expensive:

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

which processes the format string, even if the debug call does not output due to the current level of logging.

Of course, in order to work as described, the logging module used must support lambdas as "lazy parameters" (as my logging module does).

The same idea can be applied to any other case of lazy evaluation to create a value for the content of a query.

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:

 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 can just use functions instead of lambdas, but for short expressions, lambdas are (c) more compact.

+1
Oct 21 '15 at 21:37
source share

I agree boringly. By the way, even using once, drop the function, most of the time you just want to use something from the operator module.

EG:

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

You want to pass a function that adds 2 elements.

Using lambda:

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

The pythonic way:

 import operator myFunction(data, operator.add) 

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

0
Sep 25 '08 at 20:26
source share

The main difference is that you cannot use def inline functions, which, in my opinion, is the most convenient way to use the lambda function. For example, when sorting a list of objects:

 my_list.sort(key=lambda o: ox) 

Therefore, I suggest retaining the use of lambda in such trivial operations that also do not benefit from the automatic documentation provided by function naming.

-one
Oct 18 '17 at 12:03 on
source share

lambda is useful for generating new functions:

 >>> def somefunc(x): return lambda y: x+y >>> f = somefunc(10) >>> f(2) 12 >>> f(4) 14 
-2
Apr 25 '09 at 8:35
source share



All Articles