Lambda: How, Why, and Why not.

A place where you can post Python-related tutorials you made yourself, or links to tutorials made by others.

Lambda: How, Why, and Why not.

Postby Mekire » Thu Oct 17, 2013 10:10 am

When I first started learning python I found lambda extremely confusing. It isn't that there is anything particularly complicated about it; but something about the syntax--as well as a name that really didn't mean anything to me--just didn't click.

What it is:
In python, lambda allows one to define simple functions in-line. It is syntactically an expression, not a statement (a function definition using def on the other hand is a statement). Understanding what this means is critical and I will return to it shortly. You will also often hear it said that with lambda, one can write anonymous functions. But before we get to that...

The name:
Why is lambda, called lambda? Well, apparently the idea was adopted from languages such as Lisp and Scheme. The ideas associated with lambda are generally equated with the paradigm of programming languages known as functional programming languages.
With regards to the name, even Guido van Rossum lamented:
Guido van Rossum wrote:I was never all that happy with the use of the "lambda" terminology, but for lack of a better and obvious alternative, it was adopted for Python.
For more on the decisions to add functional language features, read here:
Origins of Pythons “Functional” Features

How it works:
The syntax of lambda actually isn't that complicated. It takes this structure:
Code: Select all
lambda arguments : return_value
So to put it in words, we need the keyword lambda; followed by a list of arguments; a colon; and then our return value.

Let's look at a simple (and largely useless) example:
Code: Select all
square = lambda x: x**2
The above code is absolutely identical to:
Code: Select all
def square(x):
    return x**2

It creates a function which takes a single argument, and returns that number squared. It is called like any other function:
Code: Select all
>>> square(5)
25

Additional arguments can be used by separating them with commas, as in:
Code: Select all
>>> pythag = lambda x,y : (x**2+y**2)**(0.5)
>>> pythag(5,5)
7.0710678118654755

You can even--if you are so inclined--make use of *args and **kwargs:
Code: Select all
>>> sum_of_squares = lambda *args: sum(arg**2 for arg in args)
>>> sum_of_squares(4,6,2)
56

But why do we need them:
Hopefully, at this point, you are asking yourself this question. Usually the answer to this is, we don't. In fact if you are using lambda there should be a very good reason. Writing short little functions as just demonstrated, is not a good enough reason.

The two primary reasons for using lambda are:
  1. You are writing a function that returns a function.
  2. You are writing a short callback function.
1.
Let's look at number one; functions that return functions. Let's modify our previous square function so that we can use any power we want:
Code: Select all
def power_of(power):
    return lambda x: x**power
We now have a function that returns a lambda. And this is how we use it:
Code: Select all
>>> square = power_of(2)
>>> cube = power_of(3)
>>> fourth = power_of(4)
>>> square(8)
64
>>> cube(8)
512
>>> fourth(8)
4096
At this point we get our first glimpse of what "Anonymous function" means. The lambda function that was returned was never actually assigned to a name.

I would also like to note at this point something that a lot of people seem to miss when they start out. We didn't need to use lambda for this function at all. The previous power_of function is identical to this:
Code: Select all
def power_of(power):
    def pow_it(x):
        return x**power
    return pow_it
In this version we explicitly defined a function within our power_of function; and then returned it. The enclosed function is no longer anonymous.

2.
Now let's look at the second reason I listed for using lambda; you are writing a callback function. Basically a callback function is a function that you pass as an argument to another function. The most commonly seen example of this is with regards to sort/sorted.

Take the following list of tuples:
Code: Select all
data = [(0,4), (5,3), (5,2), (6,1), (7,9), (0,12), (2,1)]
If we sort this list (either by the sorted builtin or the list.sort method) we get the following:
Code: Select all
>>> print(sorted(data))
[(0, 4), (0, 12), (2, 1), (5, 2), (5, 3), (6, 1), (7, 9)]
The items by default sorted with preference for the first item; but what if we wanted to sort by the second item? Well, the sort/sorted methods take an optional key argument. This key is a callback function dictating how the list should be sorted.

We could manually write a callback function and use it:
Code: Select all
def order_by_second(item):
    return item[1]
Code: Select all
>>> print(sorted(data, key=order_by_second))
[(6, 1), (2, 1), (5, 2), (5, 3), (0, 4), (7, 9), (0, 12)]
But most agree this is a bit silly.

The accepted way to pass simple callbacks, is by using lambda:
Code: Select all
>>> print(sorted(data, key=lambda item:item[1]))
[(6, 1), (2, 1), (5, 2), (5, 3), (0, 4), (7, 9), (0, 12)]

This is when understanding the distinction between statement and expression becomes important. As def is a statement, we could never actually define a function while passing it as an argument at the same time. Statements can not appear in such locations. The fact that lambda is an expression gives us the freedom we need to anonymously create and pass simple functions such as this. Along with being able to pass these functions immediately as arguments, you also have the freedom to do other things like place them in dictionaries.

For example, this code in which three simple functions are defined and placed in a dictionary:
Code: Select all
def rook(x,y):
    return x+y

def queen(x,y):
    return max(x,y)

def knight(x,y):
    return max((x//2+x%2),(y//2+y%2))

HEURISTICS = {"rook"   : rook,
              "queen"  : queen,
              "knight" : knight}

Would become as short and simple as this:
Code: Select all
HEURISTICS = {"rook"   : lambda x,y : x+y,
              "queen"  : lambda x,y : max(x,y),
              "knight" : lambda x,y : max((x//2+x%2),(y//2+y%2))}

While lambda can be a very neat tool, knowing when it is appropriate to use a lambda is just as important as knowing when not to. You would do well to be aware that Guido van Rossum strongly considered removing lambda from the language completely when Python 3 was first being released. He certainly has justified reasons for this.

-Mek
User avatar
Mekire
 
Posts: 816
Joined: Thu Feb 07, 2013 11:33 pm
Location: Amakusa, Japan

Re: Lambda: How, Why, and Why not.

Postby metulburr » Sun Dec 29, 2013 2:31 am

one of the most used times of using lambda is in Tkinter when you need a callback function with arguments.
here is a prefect example:
viewtopic.php?f=6&t=10118
New Users, Read This
version Python 3.3.2 and 2.7.5, tkinter 8.5, pyqt 4.8.4, pygame 1.9.2 pre
OS Ubuntu 14.04, Arch Linux, Gentoo, Windows 7/8
https://github.com/metulburr
User avatar
metulburr
 
Posts: 1103
Joined: Thu Feb 07, 2013 4:47 pm
Location: Elmira, NY

Re: Lambda: How, Why, and Why not.

Postby Mekire » Mon Dec 30, 2013 2:06 am

I agree; they are very useful to this end.

They are of course, still not required, but they can be very convenient.

If your callback is sufficiently complicated I would still recommend writing a proper function and passing that instead.

-Mek
User avatar
Mekire
 
Posts: 816
Joined: Thu Feb 07, 2013 11:33 pm
Location: Amakusa, Japan


Return to Tutorials

Who is online

Users browsing this forum: No registered users and 3 guests