Other resources: Using Python Lambda Functions [tutorial]
Understanding Lambdas
00:00 In the previous lesson, I showed you how Python functions are also objects. In this lesson, I’ll show you Python’s anonymous inline function-like thing: lambdas.
00:10 In some programming languages, a function call is pretty cheap. For example, in a lot of compiled languages, it really is just about moving the address pointer to a new block of code.
00:19 Since functions are objects in Python, they have a bit more overhead, not overhead you should worry about too much. The answer isn’t to stop using functions, but they’re heavier than in some other languages.
00:31
And sometimes you might want something a little lighter weight. In a previous lesson, I showed you how to use the key argument to the sorted() function.
00:38 That argument takes a callable, and it would be nice to have something quick and inline you could use in that kind of situation. Well, Python has just the thing. They’re called lambdas, named after Lambda Calculus.
00:50
Lambdas are like functions, but they’re anonymous. That means you don’t use the def keyword and create a name. You define a lambda right where it is, either assigning it to a variable as a reference, or calling it in place.
01:03
Because of this structure, they can be used inline. Back to that sorted() example, you could define a lambda directly on the key argument, right in the sorted() function call. There is a major restriction, though: they’re limited to a single statement.
01:18
That means you can’t do anything that requires a block, like if, for, or with. The upside of this restriction is the interpreter can optimize lambdas quite well.
01:27 Off to the REPL for a quick tangent, and then I’ll show you how to use lambdas in your code. The first lambda I’m going to show you reverses a string, but before creating that, I want to go a little tangential to show you how the common string reversing shortcut works.
01:43
First, I need something to reverse, and of course, I can use square brackets to get at parts of that string. 0:8 is called a slice and it results in the first through eighth characters.
01:57 This can be easy to mess up and be off by one. Remember, an index is zero-based and a slice is exclusive, meaning that eight is the position to stop before including.
02:07 This can take a bit of getting used to, but there’s deeply thought-out computer science behind the choice. Since you’re taking a course on functional programming, I suspect you’ve seen all this stuff before and are probably right now reaching for the fast forward button, but there’s a lesser-used part to slicing though.
02:25
You can use a third parameter to indicate the step size in the slice. Here, the step size of 2, every other character is getting included. This is similar to how the range() function works with a starting value, a less than comparison value, and an optional step value as arguments.
02:43 You can leave out parts of the slice for brevity. When you aren’t explicit about the starting point, it defaults to zero.
02:53 And of course, if you leave off the start and endpoints, you can still use the step size bit, giving you every other letter.
03:02
Negative indices start from the right-hand side. So -1 gives us the ‘n’ in Python, and all of this is leading up to that reversing shortcut I was talking about.
03:13 Double colon negative one reverses a string. Sometimes you see this explained as a magic trick, but it isn’t something special. The compiler isn’t changing its behavior just for this result.
03:24 It’s a consequence of using the default start and end value for a slice, and then a negative value for the step, which means to step backwards. I’ve been demonstrating this on a string, but it works on any sequence.
03:45 Doing it on a list gives the list in backwards order. Alright, now that you’ve seen the trick and why it works, let’s do some backwards stuff.
04:00 Quick little function to encapsulate what I showed you,
04:06 and a test to show that it works. What if I want to create a list where all the items are backwards?
04:26
Here, I’ve looped through the interval, calling backwards on each item, but what instead of reversing it, I just wanted to sort based on this idea?
04:34
You’ll recall from an earlier lesson that you can pass a function reference to sorted().
04:43
Note that the result itself doesn’t contain the backwards strings, but the sorting order is based on that. The e in 'vole' is before the g in 'dog', etc.
04:54 Okay, tangent complete. I promise all that served a purpose. I’m going to build some lambdas that use these same ideas.
05:07
Here, I’ve defined a lambda, and put it in a variable named also_backwards. You declare a lambda using the lambda keyword. A lambda can take arguments.
05:17
This one takes a single argument that I’ve creatively named x. The first colon is like the colon at the end of a function definition line. Everything to the right of it is the thing that gets run when the lambda gets invoked, which in this case, says to treat x like a sequence, and use our [::-1] trick to reverse it.
05:37 A lambda works a bit like a line on the REPL. The result of the statement is what gets returned. What I’ve done here is just a declaration. It creates a reference similar to the function reference you saw in the previous lesson, but it hasn’t invoked it yet.
05:56
You invoke it with parentheses just like any other callable. Here I’ve passed in the first item in the animals list, which was ferret, and the lambda has returned the reversed string.
06:07
If you look at also_backwards, it’s similar to what happens when you evaluate a function reference, except this time because it’s anonymous, instead of the function’s name, you see angle brackets, lambda.
06:20 You can use a lambda anywhere you would use a function reference,
06:29
like here with the key argument of sorted(). Of course, that means
06:39
why bother storing the lambda at all? In fact, this is their most common use, defining a quick chunk of code that gets used inline. In the previous lesson, I sorted on string length by passing a reference to the len() function.
06:52 What if I wanted it from longest to shortest though? Well, using a lambda is one approach.
07:03
sorted() actually supports a backwards argument, so this isn’t the only way to do it, but you get the idea. Let’s take a look at some slightly more complex lambdas.
07:13 First off, you can invoke a lambda directly by wrapping it in parentheses.
07:22
The first set of parentheses here makes the lambda referenceable inline. While the second set is like what you’d use to invoke any other callable, so the "Monty" string is being passed to the lambda where it is being reversed, resulting in 'ytnoM'.
07:38 A lambda can take multiple arguments. Like with a function definition, you separate the arguments with commas.
07:49
Here I’ve used a lambda that takes x and y and returns x * y + x, which I then invoked with an x of three and a y of four.
07:59 I mentioned that lambdas are restricted to a single statement, so no blocks, but that doesn’t mean you can’t have a conditional. Python supports an inline tertiary operator.
08:16 Since this is all one statement, it’s allowed. Let me try that again with a different argument.
08:28 Isn’t that odd? Well, yeah, it’s supposed to be. When you want to return multiple things from a function in Python, you usually use a tuple. You can do the same with a lambda, but with a small limitation.
08:40 You have to surround the tuple in parentheses. You can get away without the parentheses when you use a tuple with a return statement, but the compiler here needs to differentiate between the lambda portion and the next part of the line, so the parentheses are required in this case. If you don’t,
09:05
you’ll get a syntax error because Python is interpreting the x here as being outside of the declaration of the lambda, which brings me to a subtle point.
09:14 Lambdas have their own namespace. Consider the following.
09:22
You can access the z variable within the lambda,
09:30
but the declaration of x here in the lambda overrides the x in the global namespace. Within this lambda x is four, not five, and that override doesn’t change the value of the global x, so it’s a scoping mechanism similar to functions.
09:47 One last thing. You can use lambdas inside of f-strings if you want, but since you’re trying to invoke them,
09:56 you have to wrap them with parentheses like our callable examples above.
10:02
There are three very common functions that get used when using a functional programming approach. In the next lesson, I’ll introduce you to the first one, the map() function.
Become a Member to join the conversation.
