Lesson 2 of 20 · about 15 min
Functions that make functions
A function can build and return a new function. The new function remembers the variables from where it was made (a closure). lambda writes small functions in one line.
🧭 What you need first: Functions are values
A stamp maker. You tell it what you want (“PAID”, in red) and it hands you a new stamp. Later, wherever you use that stamp, it prints “PAID” in red. The stamp remembers the settings it was made with, even though the stamp maker has long since moved on to other orders.
Functions can do this too. make_multiplier(3) can hand back a brand-new function that multiplies by 3. Call make_multiplier(10) and you get a different function that multiplies by 10. Each one remembers its own number. That memory is called a closure.
Another way: a pre-set coffee machine button
A coffee machine maker programs a button: “large, extra shot.” The button remembers that order forever. Pressing it later doesn’t need you to repeat the settings, because they were baked in when the button was made.
Another way: a sealed letter
A function factory is like writing a letter and sealing it: the contents (the variables) are captured at that moment and travel with the envelope (the returned function), wherever it goes.
Watch a closure remember
Step through. After make_multiplier returns, its frame would normally vanish, but triple still needs factor, so it keeps it. Watch what factor is when triple(5) and times_ten(5) run.
Watch the code run, one step at a time
- 1def make_multiplier(factor):
- 2 def multiply(x):
- 3 return x * factor
- 4 return multiply
- 5
- 6triple = make_multiplier(3)
- 7times_ten = make_multiplier(10)
- 8print(triple(5), times_ten(5))
- 9shout = lambda s: s.upper() + "!"
- 10print(shout("hello"))
➜ yellow = the line about to run · ✓ = the line that just ran
The real words
- Nested function: a
definside another function. It can read the outer function’s variables. - Returning a function:
return multiply(no brackets) hands back the function itself, not a result. - A closure is a function together with the variables it captured from where it was defined.
triplecarriesfactor = 3with it. - A function factory is a function that makes customized functions. Closely related is currying: turning a function of two arguments,
f(x, y), intof(x)(y). - lambda makes a small anonymous function from a single expression:
double = lambda x: x * 2 # same as: def double(x): return x * 2
sorted(people, key=lambda p: p.age)Lambdas can’t contain statements (no if blocks, loops or return), only one expression. If it needs a name or more than one line, use def.
- Function composition: building a new function from two others,
compose(f, g)returnslambda x: f(g(x)).
A function factory
Write make_adder(n) that returns a function that adds n to its argument. Then write compose(f, g) that returns a new function computing f(g(x)).
Lambda practice
What does (lambda x: lambda y: x - y)(10)(3) give?
triple = make_multiplier(3). Later, triple(5) still knows factor is 3. Why?
Got it?
Finish the lesson to color it in on your map and collect its concept cards.
Did this lesson click?