Quiz
Warm-up from lesson 2-3: what does say = shout (no parentheses) do?
Functions can be built inside functions
Since functions are values, a function can create and return a new function:
def make_multiplier(factor): def multiply(n): return n * factor return multiply double = make_multiplier(2) triple = make_multiplier(3)
Here is the surprising part. make_multiplier has already finished by the time you call double(10), yet multiply still knows its factor. An inner function that keeps access to variables from the function that created it is called a closure. Each call to make_multiplier captures its own factor, so double and triple do not interfere.
Closures are not an academic curiosity. They are the machinery behind decorators (next lesson), behind callbacks that need to carry context with them, and behind every "configure once, call many times" function factory in production code.
Code exercise · python
Run this program. Two closures, two remembered factors, zero shared state.
Mutable state in a closure
A closure can also carry state that changes between calls. To reassign a captured variable you must declare it nonlocal, otherwise Python would treat the assignment as a brand-new local variable:
def make_counter(): count = 0 def counter(): nonlocal count count += 1 return count return counter
Each counter made by make_counter has private, independent state, like a tiny object without a class. Closures are the engine behind decorators in the next lesson, so make sure this example feels solid before moving on.
Code exercise · python
Your turn. Write make_greeter(greeting) that returns a function taking a name and returning "greeting, name!". Create the two greeters and produce the output shown.
Quiz
c1 = make_counter() and c2 = make_counter(). After c1(), c1(), c2(), what does c2 return?
Quiz
Inside make_counter, what happens if you delete the nonlocal line but keep count += 1?