The Pros and Cons of Lambda
The Pros and Cons of Lambda
Read about lambdas: pros, cons, and uses.
Join the DZone community and get the full member experience.Join For Free
When I first started learning Python, one of the most confusing concepts to get my head around was the lambda statement. I’m sure other new programmers get confused by it as well…
Mike’s discussion is excellent: clear, straight-forward, with useful illustrative examples. It helped me — finally — to grok lambda, and led me to write yet another lambda tutorial.
Lambda: a Tool for Building Functions
Basically, Python’s lambda is a tool for building functions (or more precisely, function objects). That means that Python has two tools for building functions: def and lambda.
Here’s an example. You can build a function in the normal way, using def, like this:
1def square_root(x): return math.sqrt(x)
or you can use lambda:
1square_root = lambda x: math.sqrt(x)
Here are a few other interesting examples of lambda:
1sum = lambda x, y: x + y # def sum(x,y): return x + y 2out = lambda *x: sys.stdout.write(" ".join(map(str,x))) 3lambda event, name=button8.getLabel(): self.onButton(event, name)
What is Lambda Good For?
A question that I’ve had for a long time is: What is lambda good for? Why do we need lambda?
The answer is:
- We don’t need lambda, we could get along all right without it. But…
- there are certain situations where it is convenient — it makes writing code a bit easier, and the written code a bit cleaner.
What kind of situations?
Well, situations in which we need a simple one-off function: a function that is going to be used only once.
Normally, functions are created for one of two purposes: (a) to reduce code duplication, or (b) to modularize code.
- If your application contains duplicate chunks of code in various places, then you can put one copy of that code into a function, give the function a name, and then — using that function name — call it from various places in your code.
- If you have a chunk of code that performs one well-defined operation — but is really long and gnarly and interrupts the otherwise readable flow of your program — then you can pull that long gnarly code out and put it into a function all by itself.
But suppose you need to create a function that is going to be used only once — called from only one place in your application. Well, first of all, you don’t need to give the function a name. It can be “anonymous”. And you can just define it right in the place where you want to use it. That’s where lambda is useful.
But, but, but… you say.
- First of all — Why would you want a function that is called only once? That eliminates reason (a) for making a function.
- And the body of a lambda can contain only a single expression. That means that lambdas must be short. So that eliminates reason (b) for making a function.
What possible reason could I have for wanting to create a short, anonymous function?
Well, consider this snippet of code that uses lambda to define the behavior of buttons in a Tkinter GUI interface. (This example is from Mike’s tutorial.)
01frame = tk.Frame(parent) 02frame.pack() 03 04btn22 = tk.Button(frame, 05 text="22", command=lambda: self.printNum(22)) 06btn22.pack(side=tk.LEFT) 07 08btn44 = tk.Button(frame, 09 text="44", command=lambda: self.printNum(44)) 10btn44.pack(side=tk.LEFT)
The thing to remember here is that a tk.Button expects a function object as an argument to the command parameter. That function object will be the function that the button calls when it (the button) is clicked. Basically, that function specifies what the GUI will do when the button is clicked.
So we must pass a function object in to a button via the command parameter. And note that — since different buttons do different things — we need a different function object for each button object. Each function will be used only once, by the particular button to which it is being supplied.
So, although we could code (say)
01def __init__(self, parent): 02 """Constructor""" 03 frame = tk.Frame(parent) 04 frame.pack() 05 06 btn22 = tk.Button(frame, 07 text="22", command=self.buttonCmd22) 08 btn22.pack(side=tk.LEFT) 09 10 btn44 = tk.Button(frame, 11 text="44", command=self.buttonCmd44) 12 btn44.pack(side=tk.LEFT) 13 14def buttonCmd22(self): 15 self.printNum(22) 16 17def buttonCmd44(self): 18 self.printNum(44)
it is much easier (and clearer) to code
01def __init__(self, parent): 02 """Constructor""" 03 frame = tk.Frame(parent) 04 frame.pack() 05 06 btn22 = tk.Button(frame, 07 text="22", command=lambda: self.printNum(22)) 08 btn22.pack(side=tk.LEFT) 09 10 btn44 = tk.Button(frame, 11 text="44", command=lambda: self.printNum(44)) 12 btn44.pack(side=tk.LEFT)
When a GUI program has this kind of code, the button object is said to “call back” to the function object that was supplied to it as its command.
So we can say that one of the most frequent uses of lambda is in coding “callbacks” to GUI frameworks such as Tkinter and wxPython.
This all seems pretty straight-forward. So…
Why is Lambda So Confusing?
There are four reasons that I can think of.
First Lambda is confusing because: the requirement that a lambda can take only a single expression raises the question: What is an expression?
A lot of people would like to know the answer to that one. If you Google around a bit, you will see a lot of posts from people asking “In Python, what’s the difference between an expression and a statement?”
One good answer is that an expression returns (or evaluates to) a value, whereas a statement does not. Unfortunately, the situation is muddled by the fact that in Python an expression can also be a statement. And we can always throw a red herring into the mix — assigment statements like a = b = 0 suggest that Python supports chained assignments, and that assignment statements return values. (They do not. Python isn’t C.)
In many cases when people ask this question, what they really want to know is: What kind of things can I, and can I not, put into a lambda?
And for that question, I think a few simple rules of thumb will be sufficient.
- If it doesn’t return a value, it isn’t an expression and can’t be put into a lambda.
- If you can imagine it in an assignment statement, on the right-hand side of the equals sign, it is an expression and can be put into a lambda.
Using these rules means that:
- Assignment statements cannot be used in lambda. In Python, assignment statements don’t return anything, not even None (null).
- Simple things such as mathematical operations, string operations, list comprehensions, etc. are OK in a lambda.
- Function calls are expressions. It is OK to put a function call in a lambda, and to pass arguments to that function. Doing this wraps the function call (arguments and all) inside a new, anonymous function.
- In Python 3, print became a function, so in Python 3+, print(…) can be used in a lambda.
- Even functions that return None, like the print function in Python 3, can be used in a lambda.
- Conditional expressions, which were introduced in Python 2.5, are expressions (and not merely a different syntax for an if/else statement). They return a value, and can be used in a lambda.
1lambda: a if some_condition() else b 2lambda x: ‘big’ if x > 100 else ‘small’
Second Lambda is confusing because: the specification that a lambda can take only a single expression raises the question: Why? Why only one expression? Why not multiple expressions? Why not statements?
For some developers, this question means simply Why is the Python lambda syntax so weird? For others, especially those with a Lisp background, the question means Why is Python’s lambda so crippled? Why isn’t it as powerful as Lisp’s lambda?
The answer is complicated, and it involves the “pythonicity” of Python’s syntax. Lambda was a relatively late addition to Python. By the time that it was added, Python syntax had become well established. Under the circumstances, the syntax for lambda had to be shoe-horned into the established Python syntax in a “pythonic” way. And that placed certain limitations on the kinds of things that could be done in lambdas.
Frankly, I still think the syntax for lambda looks a little weird. Be that as it may, Guido has explained why lambda’s syntax is not going to change. Python will not become Lisp.
Third Lambda is confusing because: lambda is usually described as a tool for creating functions, but a lambda specification does not contain a return statement.
The return statement is, in a sense, implicit in a lambda. Since a lambda specification must contain only a single expression, and that expression must return a value, an anonymous function created by lambda implicitly returns the value returned by the expression. This makes perfect sense.
Still — the lack of an explicit return statement is, I think, part of what makes it hard to grok lambda, or at least, hard to grok it quickly.
Fourth Lambda is confusing because: tutorials on lambda typically introduce lambda as a tool for creating anonymous functions, when in fact the most common use of lambda is for creating anonymous procedures.
Back in the High Old Times, we recognized two different kinds of subroutines: procedures and functions. Procedures were for doing stuff, and did not return anything. Functions were for calculating and returning values. The difference between functions and procedures was even built into some programming languages. In Pascal, for instance, procedure and function were different keywords.
In most modern languages, the difference between procedures and functions is no longer enshrined in the language syntax. A Python function, for instance, can act like a procedure, a function, or both. The (not altogether desirable) result is that a Python function is always referred to as a “function”, even when it is essentially acting as a procedure.
Although the distinction between a procedure and a function has essentially vanished as a language construct, we still often use it when thinking about how a program works. For example, when I’m reading the source code of a program and see some function F, I try to figure out what F does. And I often can categorize it as a procedure or a function — “the purpose of F is to do so-and-so” I will say to myself, or “the purpose of F is to calculate and return such-and-such”.
So now I think we can see why many explanations of lambda are confusing.
First of all, the Python language itself masks the distinction between a function and a procedure.
Second, most tutorials introduce lambda as a tool for creating anonymous functions, things whose primary purpose is to calculate and return a result. The very first example that you see in most tutorials (this one included) shows how to write a lambda to return, say, the square root of x.
But this is not the way that lambda is most commonly used, and is not what most programmers are looking for when they Google “python lambda tutorial”. The most common use for lambda is to create anonymous procedures for use in GUI callbacks. In those use cases, we don’t care about what the lambda returns, we care about what it does.
This explains why most explanations of lambda are confusing for the typical Python programmer. He’s trying to learn how to write code for some GUI framework: Tkinter, say, or wxPython. He runs across examples that use lambda, and wants to understand what he’s seeing. He Googles for “python lambda tutorial”. And he finds tutorials that start with examples that are entirely inappropriate for his purposes.
So, if you are such a programmer — this tutorial is for you. I hope it helps. I’m sorry that we got to this point at the end of the tutorial, rather than at the beginning. Let’s hope that someday, someone will write a lambda tutorial that, instead of beginning this way
Lambda is a tool for building anonymous functions.
begins something like this
Lambda is a tool for building callback handlers.
So there you have it. Yet another lambda tutorial.
Opinions expressed by DZone contributors are their own.