Closures and Free Variables
Capture state in inner functions.
Closures and Free Variables is a free Python Academy lesson on CoddyKit — lesson 2 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Python Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Nested functions
Python lets you define a function inside another function. The inner function is created fresh each time the outer one runs.
def outer():
def inner():
return 'from inner'
return inner()
print(outer())Inner sees outer variables
An inner function can read variables defined in the enclosing function. These are called free variables because they are not local to the inner function.
def outer():
message = 'hello'
def inner():
return message
return inner()
print(outer())What is a closure?
A closure happens when an inner function is returned and still remembers the free variables from its enclosing scope, even after that scope has finished.
def make_greeter(name):
def greet():
return 'Hi ' + name
return greet
g = make_greeter('Ada')
print(g())Captured state survives
The outer function has already returned, yet the closure still holds onto name. The value lives on inside the returned function.
def make_greeter(name):
def greet():
return 'Hi ' + name
return greet
a = make_greeter('Ada')
b = make_greeter('Bob')
print(a())
print(b())A multiplier factory
Closures shine as factories that produce customized functions. Here each returned function multiplies by a captured factor.
def multiplier(factor):
def multiply(n):
return n * factor
return multiply
double = multiplier(2)
triple = multiplier(3)
print(double(10))
print(triple(10))Each closure is independent
Every call to the factory creates a separate closure with its own captured value. They do not interfere with each other.
def adder(amount):
def add(n):
return n + amount
return add
add5 = adder(5)
add100 = adder(100)
print(add5(1), add100(1))Inspecting closed-over values
The captured names are listed in __code__.co_freevars, and their values live in __closure__ cells.
def make(x):
def f():
return x
return f
fn = make(42)
print(fn.__code__.co_freevars)
print(fn.__closure__[0].cell_contents)Closures capture variables, not values
A closure captures the variable itself, so it sees the variable's final value. This matters when the variable changes after the closure is created.
def build():
x = 1
def show():
return x
x = 99
return show
print(build()())The late-binding loop trap
A classic gotcha: closures made in a loop all share the same loop variable, so they capture its last value.
funcs = []
for i in range(3):
funcs.append(lambda: i)
print([f() for f in funcs])Fixing late binding
Bind the current value with a default argument so each closure captures its own copy at definition time.
funcs = []
for i in range(3):
funcs.append(lambda i=i: i)
print([f() for f in funcs])Closures as lightweight objects
A closure bundles data with behavior, much like a tiny object — often cleaner than a full class for simple cases.
def counter_start(start):
def value():
return start
return value
c = counter_start(10)
print(c())Quick Check
What is a closure in Python?
Recap: Closures and Free Variables
Key ideas:
- Inner functions can read enclosing-scope variables (free variables).
- A closure is a returned inner function that remembers those variables.
- Each factory call creates an independent closure.
- Closures capture variables, not values, which causes the late-binding loop trap — fix it with a default argument.
def power_of(exp):
return lambda base: base ** exp
square = power_of(2)
print(square(9))Frequently asked questions
Is the “Closures and Free Variables” lesson free?
Yes — the full text of “Closures and Free Variables” is free to read here on the web, and the Python Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Python Academy course, upgrade to CoddyKit PRO.
What will I learn in “Closures and Free Variables”?
Capture state in inner functions. You practise Python Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Python Academy?
No prior experience is required. Python Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Closures and Free Variables” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Python Academy lesson?
Yes. Every Python Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- First-Class Functions
- Closures and Free Variables
- nonlocal and Mutable State
- Partial Functions