Skip to main content

Command Palette

Search for a command to run...

Closure In Python

Updated
4 min read
Closure In Python
U

Transformative Tech Leader | Serial Entrepreneur & Machine Learning Engineer Leveraging 3+ years of expertise in Machine Learning and a background in Web Development, I drive innovation through building, mentoring, and educating. Passionate about harnessing AI to solve real-world problems."

By the end of this lesson, you’ll:

  • Know what a closure is,

  • Understand how closures work internally,

  • Learn why we use closures,

  • See practical real-world examples,

  • And get practice exercises to solidify your understanding.


1. What is a Closure in Python?

A closure is a function that remembers variables from its enclosing scope, even if that scope is no longer active.

In other words:

A closure allows a function to access variables from outside its immediate scope, even after the outer function has finished executing.


Example (without closure)

def outer_function():
    x = 10
    def inner_function():
        print(x)
    inner_function()

outer_function()

Output:

10

Here, inner_function() accesses x from the outer scope — that’s normal.

But now watch what happens if we return the inner function.


2. How Closures Are Created

Step-by-step Example:

def outer_function():
    x = 10   # <- This variable is in the enclosing scope

    def inner_function():
        print(x)  # <- inner_function refers to x

    return inner_function   # <- returning the function, not calling it

my_func = outer_function()  # outer_function() executes and returns inner_function
my_func()  # we call the returned function

Output:

10

What happened internally?

  • When outer_function() ran, it created x = 10 and defined inner_function.

  • Then it returned inner_function.

  • Normally, when a function finishes, its local variables (x) are destroyed.

  • But because inner_function remembers x, it stays alive inside the returned function.

That “remembering” is called a closure.


3. Checking if a function is a closure

You can inspect the closure using the __closure__ attribute:

def outer_function():
    x = 5
    def inner_function():
        print(x)
    return inner_function

f = outer_function()
print(f.__closure__)  # <--- contains the remembered variables

Output:

(<cell at 0x...: int object at 0x...>,)

You can even look inside the closure cell:

print(f.__closure__[0].cell_contents)

Output:

5

That’s how Python stores the enclosed variable.


4. Why Use Closures?

Closures are very powerful and used frequently in Python to:

  1. Preserve state without using global variables or classes.

  2. Encapsulate logic neatly.

  3. Build function factories (functions that return customized functions).

  4. Implement decorators (a key part of advanced Python).


Example 1: Function Factory

You can use closures to create customized functions.

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

double = multiplier(2)
triple = multiplier(3)

print(double(5))  # 10
print(triple(5))  # 15

Here:

  • Each returned function (double, triple) “remembers” its own factor.

  • factor stays alive even after multiplier() finishes.


Example 2: Simple Counter

Closures can maintain state between function calls.

def counter():
    count = 0
    def increment():
        nonlocal count   # allows modification of outer variable
        count += 1
        return count
    return increment

count1 = counter()
print(count1())  # 1
print(count1())  # 2
print(count1())  # 3

Without nonlocal, Python would treat count as a new local variable inside increment().


Example 3: Configuration Wrapper

Suppose you want to wrap behavior around a specific configuration.

def greet_config(lang):
    def greet(name):
        if lang == "en":
            print(f"Hello, {name}!")
        elif lang == "es":
            print(f"Hola, {name}!")
        else:
            print(f"Hi, {name}!")
    return greet

english_greet = greet_config("en")
spanish_greet = greet_config("es")

english_greet("Alice")
spanish_greet("Carlos")

Output:

Hello, Alice!
Hola, Carlos!

Each function remembers its lang configuration.


5. Important Keyword: nonlocal

When using closures, the inner function cannot modify variables from the enclosing scope unless you declare them as nonlocal.

Example:

def outer():
    count = 0
    def inner():
        nonlocal count
        count += 1
        return count
    return inner

f = outer()
print(f())  # 1
print(f())  # 2

Without nonlocal, you’d get an error:

UnboundLocalError: local variable 'count' referenced before assignment


7. Real-World Use Cases of Closures

  1. Decorators — Python decorators are implemented using closures.

     def logger(func):
         def wrapper(*args, **kwargs):
             print(f"Running {func.__name__}...")
             return func(*args, **kwargs)
         return wrapper
    
     @logger
     def greet(name):
         print(f"Hello, {name}")
    
     greet("John")
    
  2. Data hiding — Closures let you encapsulate variables.

  3. Callbacks — Used in event handling (e.g., in GUIs or async code).

  4. Custom Function Generators — Like multiplier() above.


8. Practice Exercises

Exercise 1: Function Factory

Create a closure power_of(n) that returns a function which raises any number to the power n.

Expected:

square = power_of(2)
cube = power_of(3)

print(square(4))  # 16
print(cube(2))    # 8

Exercise 2: Simple Banking Example

Create a closure bank_account() that:

  • Starts with a balance of 0.

  • Has an inner function transaction(amount) that can deposit or withdraw.

  • Uses nonlocal to modify the balance.

Expected:

account = bank_account()
print(account(100))   # Deposited 100 → balance = 100
print(account(-50))   # Withdrawn 50 → balance = 50

9. Summary

ConceptMeaning
ClosureA function that remembers variables from its enclosing scope
How it’s formedWhen a nested function references variables from its enclosing function and is returned
Use casesFunction factories, decorators, maintaining state, data hiding
Keywordnonlocal allows modification of enclosed variables

Key Takeaways

  • Closures make functions stateful without using classes.

  • They are foundational for decorators and many advanced Python features.

  • They provide encapsulation and flexibility in functional programming styles.


More from this blog

T

The AI Academy Blog

10 posts