Python Closures
Core Python Functions and Modules

Python Closures

1Python Closures: overview

A closure is a function that remembers the variables of the enclosing function where it was created, so it can keep using them even after that outer function has returned.

GoalBy the end you can build function factories and counters with nonlocal, explain which variables a closure remembers, inspect them with closure, avoid the late-binding loop trap, and decide between a closure and a class.

Before this lesson: Python Functions, Python Variable Scope

2Python Closures: diagram

Python ClosuresGlobal scopetriple = make_multiplier(3), triple(10) gives 30make_multiplier(3): already finished, its cell is keptfactor = 3multiply(number): the returned functionreturn number * factortriple still remembers factor = 3, although make_multiplier has returned.
The inner function sits inside the scope of the call that created it. When it is returned, it takes the variables it uses (here factor) along, which is why triple(10) still works long after make_multiplier(3) is over.

3Python Closures: explained step by step

In the scope lesson you saw that a function defined inside another function can read the outer function's variables. This lesson is about what happens when that inner function leaves the place where it was born. Python keeps the variables it needs alive, and the result is a closure: a function bundled together with the values it remembers from the scope around it.

A function that remembers

Python
def make_greeter(greeting):
    def greet(name):
        return f"{greeting}, {name}!"
    return greet                 # return the function itself: no parentheses

hello = make_greeter("Hello")
hola = make_greeter("Hola")
print(hello("Asha"))
print(hola("Ben"))

make_greeter is finished as soon as it returns, and normally its local variables would disappear with it. But greet still needs greeting, so Python keeps that value alive and attaches it to the function. hello and hola are two separate greet functions, each remembering its own greeting.

Pay attention to the last line of make_greeter. return greet hands back the function. return greet("x") would call it and hand back the text instead.

Free variables

Inside greet, the name name is local because it is a parameter. But greeting is neither local nor global: it belongs to the enclosing function. A name used in a function but defined in an enclosing scope is called a free variable, and a function with at least one free variable is a closure.

Function factories

A function that builds and returns other functions is a factory. You give it the settings once, and it hands back a specialised function you can call as often as you like:

Python
def make_multiplier(factor):
    def multiply(number):
        return number * factor
    return multiply

double = make_multiplier(2)
triple = make_multiplier(3)
print(double(10), triple(10))
print(list(map(triple, [1, 2, 3])))

Because triple takes one argument, it plugs straight into map(), filter() or sorted(key=...). A lambda that uses an outer variable, like lambda n: n * factor, is a closure too.

State that survives between calls

A closure can also change what it remembers, which gives you a function with a memory. Because count += 1 is an assignment, Python would normally treat count as a new local variable and fail. The nonlocal keyword says "this name belongs to the enclosing function":

Python
def make_counter():
    count = 0
    def step():
        nonlocal count           # change the enclosing variable, do not make a new one
        count += 1
        return count
    return step

page_views = make_counter()
downloads = make_counter()
print(page_views(), page_views(), page_views())
print(downloads())

Each call to make_counter() creates a fresh count, so the two counters never disturb each other. You only need nonlocal when you reassign the name. Changing an object it points to, such as scores.append(80) on a remembered list, needs no keyword.

Closure or class?

A class can hold the same state, and sometimes it is the better choice:

Python
class Counter:
    def __init__(self):
        self.count = 0

    def step(self):
        self.count += 1
        return self.count

page_views = Counter()
print(page_views.step(), page_views.step())
print(page_views.count)          # a class lets anyone read the state

A closure suits one small behaviour with a little private state, and nobody outside can touch count. Write a class once you need several methods, attributes people should read, or something other developers will extend.

Why not just use a global variable?

A global count would also survive between calls, but there is only one of it. Two counters would need two globals and two almost identical functions, and any code anywhere could change them by accident. A closure gives every function its own private copy, created on demand.

Peeking inside with __closure__

Python stores each remembered variable in a small cell. You will rarely need this outside of learning and debugging, but it makes the idea concrete:

Python
def make_counter():
    count = 0
    def step():
        nonlocal count
        count += 1
        return count
    return step

tally = make_counter()
tally()
tally()
print(tally.__code__.co_freevars)
cell = tally.__closure__[0]
print(cell.cell_contents)
tally()
print(cell.cell_contents)

def plain(x):
    return x

print(plain.__closure__)

co_freevars lists the remembered names, and cell_contents shows the live value. The cell changes when the function changes it. An ordinary function with no free variables has __closure__ set to None.

The loop gotcha: late binding

A closure remembers the variable, not the value the variable had when the function was created. In a loop, every function shares the same variable, and by the time you call them it holds the last value:

Python
def make_greeters(names):
    late = []
    early = []
    for name in names:
        late.append(lambda: f"Hi {name}")
        early.append(lambda name=name: f"Hi {name}")
    return late, early

late, early = make_greeters(["Asha", "Ben", "Cara"])
print([g() for g in late])
print([g() for g in early])

The first list says Cara three times. The second works because a default argument is evaluated when the lambda is created, so each function gets its own copy. Another fix is to build each function inside a small factory, so every call has its own variable.

4Python Closures: syntax

def outer(setting):                 # outer function: its variables can be remembered
    state = 0
    def inner(value):               # inner function: a closure if it uses outer's names
        nonlocal state              # only needed to REASSIGN an enclosing variable
        state += value
        return value * setting      # setting is a free variable
    return inner                    # return the function itself, no parentheses

func = outer(3)
func(10)                            # state and setting live on between calls
func.__code__.co_freevars           # names the closure remembers
func.__closure__[0].cell_contents   # peek at one remembered value

5Python Closures: run the example

Press Run (or Ctrl + Enter). The output (step 6) appears directly below the code. Change anything and run it again.

Interactive example
def make_ticket_machine(prefix):
    number = 0
    def next_ticket():
        nonlocal number
        number += 1
        return f"{prefix}-{number:03d}"
    return next_ticket

help_desk = make_ticket_machine("HELP")
billing = make_ticket_machine("BILL")
print(help_desk())
print(help_desk())
print(billing())
print(help_desk())
Expected outputHELP-001
HELP-002
BILL-001
HELP-003

7Python Closures: how the example works

Hover or tap a step to highlight its lines in the example above.

  1. Line 1-2make_ticket_machine is a factory. Each call gets its own prefix and its own number, both local to that call, and number starts at 0.
  2. Line 3next_ticket is defined inside the factory. It uses prefix and number without receiving them as parameters, so they are free variables and next_ticket is a closure.
  3. Line 4nonlocal number is required because line 5 reassigns the name. Without it, Python would treat number as a new local variable and raise an UnboundLocalError.
  4. Line 5-6Each call adds one to the remembered number and builds a ticket such as HELP-001. :03d pads the number with zeros to three digits.
  5. Line 7The factory returns the function itself, with no parentheses. After this line make_ticket_machine has finished, yet the function still remembers its two variables.
  6. Line 9-10Two separate calls create two separate closures. help_desk remembers "HELP" and its own count, and billing remembers "BILL" and a different count.
  7. Line 11-14help_desk counts 1, 2, then 3, while billing starts from 1 in the middle. The two counters never affect each other.

8Python Closures: common mistakes

Changing a remembered variable without nonlocal

✗ Wrong

def make_counter(start):
    count = start
    def increment():
        count += 1
        return count
    return increment

clicks = make_counter(0)
print(clicks())
UnboundLocalError: cannot access local variable 'count' where it is not associated with a value

✓ Right

def make_counter(start):
    count = start
    def increment():
        nonlocal count
        count += 1
        return count
    return increment

clicks = make_counter(0)
print(clicks())

count += 1 assigns to count, so Python decides count is a local variable of increment, and that local has no value yet. Declare nonlocal count first, so the name refers to the enclosing variable.

Calling the inner function instead of returning it

✗ Wrong

def make_multiplier(factor):
    def multiply(number):
        return number * factor
    return multiply(1)

double = make_multiplier(2)
print(double(10))
TypeError: 'int' object is not callable

✓ Right

def make_multiplier(factor):
    def multiply(number):
        return number * factor
    return multiply

double = make_multiplier(2)
print(double(10))

multiply(1) runs the function right away and returns a number, so double is just 2. To return the function itself, leave off the parentheses.

Creating functions in a loop that all share one variable

✗ Wrong

def make_buttons(labels):
    buttons = []
    for label in labels:
        buttons.append(lambda: "clicked " + label)
    return buttons

for button in make_buttons(["Save", "Open", "Exit"]):
    print(button())
No error, but every line says: clicked Exit

✓ Right

def make_buttons(labels):
    buttons = []
    for label in labels:
        buttons.append(lambda label=label: "clicked " + label)
    return buttons

for button in make_buttons(["Save", "Open", "Exit"]):
    print(button())

Every lambda remembers the same variable label, and after the loop it holds "Exit". Freeze the current value with a default argument (lambda label=label: ...) or build each function in a small factory.

Using nonlocal for a global variable

✗ Wrong

total = 0

def add(amount):
    nonlocal total
    total += amount

add(5)
print(total)
SyntaxError: no binding for nonlocal 'total' found

✓ Right

def make_total():
    total = 0
    def add(amount):
        nonlocal total
        total += amount
        return total
    return add

add = make_total()
add(5)
print(add(3))

nonlocal only works for a variable of an enclosing function. A top-level variable is global. Better still, keep the state in a closure so nothing global is needed.

Calling the factory again for every use

✗ Wrong

def make_counter():
    count = 0
    def step():
        nonlocal count
        count += 1
        return count
    return step

print(make_counter()())
print(make_counter()())
print(make_counter()())
No error, but it prints 1 three times instead of 1, 2, 3

✓ Right

def make_counter():
    count = 0
    def step():
        nonlocal count
        count += 1
        return count
    return step

counter = make_counter()
print(counter())
print(counter())
print(counter())

Every make_counter() call builds a brand-new counter with its own count. Call the factory once, keep the returned function in a variable, and call that variable each time.

9Python Closures: exercises

Write your answer, then press Check. The checks run in your browser.

1. Build an adder factory

Write code Easy

Write a function make_adder(amount) that returns a new function. The returned function takes one number and returns that number plus amount. Then create add_ten = make_adder(10) and print add_ten(5).

Your code
def make_adder(amount):
    # define an inner function that adds amount, and return it
    pass

add_ten = make_adder(10)
print(add_ten(5))

2. Predict the late-binding prices

Predict the output Medium

Two lists of functions are built in a loop. One list uses plain lambdas, the other freezes the value with a default argument. After the loop the variable discount is changed once more. Type exactly what the program prints.

Read this code
def make_prices():
    shown = []
    frozen = []
    for discount in [10, 20, 30]:
        shown.append(lambda: 100 - discount)
        frozen.append(lambda discount=discount: 100 - discount)
    discount = 50
    return shown, frozen

shown, frozen = make_prices()
print([f() for f in shown])
print([f() for f in frozen])

2 more exercises → 6 more examples

Finished this lesson?
Progress is saved in this browser — create a free account to keep it across devices.

Questions learners ask

What is the difference between nonlocal and global in Python?

global makes a name refer to a variable at the top level of the file, while nonlocal makes it refer to a variable of the nearest enclosing function. Both are only needed when you assign to the name. Using nonlocal for something that is not in an enclosing function is a SyntaxError.

Is every inner function or lambda a closure?

No. It becomes a closure only if it uses a variable from an enclosing function. A nested function that uses only its own parameters has closure set to None. You can check any function by printing func.closure: a tuple of cells means it is a closure, and None means it is not.

Should I use a closure or a class to keep state between calls?

Use a closure when you need one small behaviour with a little private state, such as a counter or a configured helper. Use a class when you need several related methods, attributes that other code should read, or objects that people will extend. The class is usually clearer as the program grows.

Further reading

10Next lesson

Up nextPython DecoratorsA decorator is a function that takes another function, wraps extra behaviour around it and returns the wrapped version;…

Related:
Python Lambda FunctionsPython RecursionPython Variable ScopePython Decorators

← Python Variable Scope · All Functions and Modules lessons · Practise in the IDE