[Tutor] Demystification of Lambda Functions

Steven D'Aprano steve at pearwood.info
Wed Oct 28 07:36:49 EDT 2015


On Tue, Oct 27, 2015 at 09:04:45PM -0400, Hunter Jozwiak wrote:
> Hello,
> 
> I am not sure exactly why there would be a practical use for a lambda
> function, other than the fact that you can make one-liner functions that
> take parameters in to a variable. Or at least that is how things look when
> they are written. Can I have some demystification?

To understand why lambda is useful will require a bit of background. So 
let me start at the beginning.

The first thing you have to understand is that in modern languages like 
Python, functions are not just things that operate on values, but they 
are values themselves. So you can have a function which returns a new 
function as its result. Here is a simple example:

py> def make_adder(n):
...     def adder(x):
...             return x + n
...     return adder
...
py> add_one = make_adder(1)
py> add_one(100)
101
py> add_five = make_adder(5)
py> add_five(100)
105

"make_adder" is a function which takes an argument, n, and returns a new 
function which takes one argument and returns that value plus the 
earlier value "n". So make_adder(1) builds a function that adds 1 to its 
argument, and make_adder(2) builds a function that adds 5 to its 
argument.

Functions can not merely return functions, they can also take them as an 
argument. Here's a simple example:


py> def add(a, b):  # Function that adds two values.
...     return a + b
...
py> def times(a, b):  # Function that multiplies two values.
...     return a*b
...
py> def builder(func):
...     def op3(x):
...             return func(x, 3)
...     return op3
...
py> add_three = builder(add)
py> add_three(5)
8
py> times_three = builder(times)
py> times_three(5)
15


Now, those two examples themselves aren't terribly useful, it isn't very 
often that you need a whole bunch of functions:

add_one
add_two
add_three 

etc. But the ability to manipulate functions as arguments itself is 
useful. For example, suppose you have a set of strings, and you need to 
find out how long they all are:

py> strings = ["cat", "dog", "cheese", "aardvark", "elephant", "hamburger"]
py> lengths = []
py> for s in strings:
...     lengths.append(len(s))
...
py> print lengths
[3, 3, 6, 8, 8, 9]


Having to build up a list yourself is a bit tedious, but there's another 
way:

py> print map(len, strings)  # Python 2 version.
[3, 3, 6, 8, 8, 9]


The "map" function takes a function (in this case, len) and applies it 
to each item in strings, consolidating the results. The Python 3 version 
is a little different, but the basic concept remains the same.

Suppose we had a list of numbers, and we wanted to create a new list 
with each number doubled and then one added. We could do this:

py> def double_and_add_one(x):
...         return 2*x + 1
...
py> map(double_and_add_one, [2, 3, 4, 5])
[5, 7, 9, 11]


but it seems a bit wasteful to have that function "double_and_add_one" 
floating around in our program after we've used it, doing nothing 
useful. It has a name and everything.

Python lets us create an unnamed function, right there in the expression 
where it is being used. Once used, the interpreter can delete the 
function and reclaim its memory. To do this, we use lambda:

py> map(lambda x: 2*x+1, [2, 3, 4, 5])
[5, 7, 9, 11]


If you have a function that looks like this:

def FUNCTION(args):
    return EXPRESSION

that can be written using the lambda syntax:

lambda args: EXPRESSION

dropped right in the place where you are planning to use it, instead of 
having to pre-define it using "def".

That makes lambda especially convenient for callback functions. For 
example, many GUI toolkits let you set callbacks. Suppose you create a 
button using some toolkit, like this, say:

save_button = Button("save", style="round")

What does the button do? So far, nothing: you can click on it, and 
nothing happens. To give the button an action, you have to give it a 
callback function. A callback is a function that the button will call 
when you click on it:

def save(thebtn):
    # whatever code you need to save the document

save_button = Button("save", style="round", callback=save)


Sometimes callbacks are particularly short and simple. Suppose you are 
programming a calculator, and you have ten buttons 0...9 which all do 
precisely the same thing: they add their own name to the calculator 
display:


for num in range(0, 10):
    btn = Button(str(num), style="rectangle", 
                 callback = lambda thebtn: display.add(thebtn.name)
                 )


Much better than having to pre-define ten functions and add them to each 
of the buttons.

These functions are called "anonymous functions", because unlike 
functions created with "def", they don't have a name. Well, technically 
they do, but they're all the same name:

py> (lambda x: x+1).__name__
'<lambda>'

which is only used for display, say, if there is an error. What makes 
anonymous functions especially useful in languages other than Python is 
that they are created at runtime, not compile-time, so they can include 
information that is only known when the program runs. They are also 
expressions, not statements, so you can use them wherever you might use 
some other expression:


things = [123, "something", lambda x: x+1, {}, None]

You can't imbed a "def" inside a list, you have to define the function 
first (giving it a name), then put it in the list:

things = [123, "something"]
def add_one(x):
    return x + 1
things.append(add_one)
things.append({})
things.append(None)


So lambda is useful for writing small, simple, use-once and throw-away 
functions.

There are two things to remember about lambda:

- Functions that you create with lambda are exactly the same as those 
you create with def (apart from the lack of a name). def and lambda 
don't create two different kinds of function, they are the same kind of 
function. Only the syntax (and name) is different.

- lambda syntax is restricted to a single expression. So you can't 
write:

lambda x: y = []
          y.append(x)
          return y

that will give a syntax error.


Any further questions, feel free to ask.


-- 
Steve


More information about the Tutor mailing list