logo
33

Closures

⏱️ 25 min

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)

  1. Implement a basic counter closure.
  2. Modify it to step by 2.
  3. 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 nonlocal correctly
  • 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: nonlocal and global are interchangeable.

  • Reality: nonlocal targets the enclosing local scope. global targets module-level variables.