Closures
Closures: Functions That Remember Their Context
What might confuse you right now
"Shouldn't variables get destroyed after the outer function finishes?"
In a closure, variables referenced by the inner function stick around. That's how you get "functions with state."
One-line definition
A closure is an inner function + the captured outer variable environment.
Real-life analogy
Think of a dedicated counter remote control: the remote still exists, so the internal count state still exists too.
Minimal runnable example
def make_counter():
count = 0
def counter():
nonlocal count
count += 1
return count
return counter
c = make_counter()
print(c()) # 1
print(c()) # 2
Factory function example
def make_multiplier(factor):
def mul(x):
return x * factor
return mul
triple = make_multiplier(3)
print(triple(5)) # 15
Quick quiz (5 min)
- Implement a basic counter closure.
- Modify it to step by 2.
- Write
make_discount(rate)that returns a discount function.
Quiz answer guidelines & grading criteria
- Answer direction: working code that covers core conditions and edge inputs from the prompt.
- Criterion 1 (Correctness): Main flow produces correct results, key branches execute.
- Criterion 2 (Readability): Clear variable names, no excessive nesting.
- Criterion 3 (Robustness): Basic protection against null values, type errors, or unexpected input.
Transfer task (homework)
Build a "retry function factory": make_retry(max_retry) returns an executor with retry logic baked in.
Acceptance criteria
You can independently:
- Explain why closures retain state
- Use
nonlocalcorrectly - Use closures to encapsulate config in simple business logic
Common errors & debugging steps (beginner edition)
- Can't understand the error: read the last line for the error type (e.g.,
TypeError,NameError), then trace back to the relevant code line. - Not sure about a variable's value: temporarily add
print(variable, type(variable))at key points to verify data matches expectations. - Code changes aren't taking effect: confirm the file is saved, you're running the right file, and your terminal environment (venv) is correct.
Common misconceptions
-
Misconception: All nested functions are closures.
-
Reality: It's only a closure if it captures outer variables and is used outside that scope.
-
Misconception:
nonlocalandglobalare interchangeable. -
Reality:
nonlocaltargets the enclosing local scope.globaltargets module-level variables.