🚀 Welcome to the World of Closures

Alright, young coder! You’ve made it to one of the coolest and most brain-tingling parts of Python functions — Closures.

Let’s explore closures like we’re in a secret coding workshop, building little magic tools that remember things 🧠💼.


🧠 What Are Closures? (Think: Backpack Trick)

Imagine you’re packing a backpack 🎒 with snacks 🍫 and a notebook 📓. Then you zip it up and give it to a friend. Even though you’re gone, your friend can still unzip it and use what’s inside.

That’s exactly what a closure is in Python.

📌 In our code analogy:

  • The backpack = a function defined inside another function.
  • The snacks = variables from the outer (enclosing) function.
  • The friend using it later = Python remembering those variables even after the outer function is done.

💻 Python Closure Example

Let’s see this concept in action:

def outer():
    count = 0

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

    return inner

🛠 Line-by-Line Breakdown:

  • outer() is our “backpack-packing” function.
  • Inside it, we define count = 0.
  • Then we define inner(), a helper function that adds 1 to count.
  • Instead of calling inner(), we return it — the backpack is zipped up and handed off.

Now try this:

counter = outer()
print(counter())  # Output: 1
print(counter())  # Output: 2
print(counter())  # Output: 3

Even though outer() has finished running, the inner() function remembers count. That’s the magic of closures.


🤖 Closures Are Functions with Memory

A closure is a function that:

  • is defined inside another function,
  • uses variables from the outer function,
  • and remembers those variables even after the outer function is done.

This allows you to create dynamic, customized functions with persistent state.


🎮 Real-Life Use Case: A Game Score Tracker

Suppose you’re building a simple game and want to track a player’s score without using global variables. Closures are perfect for this.

def create_score_tracker():
    score = 0

    def add_points(points):
        nonlocal score
        score += points
        return score

    return add_points

Use it like this:

player1 = create_score_tracker()
print(player1(10))  # Output: 10
print(player1(5))   # Output: 15

player2 = create_score_tracker()
print(player2(7))   # Output: 7

Each player gets their own closure, with their own score stored safely inside. Beautiful, right?


🛑 But Wait — What if nonlocal Doesn’t Work?

You may have tried this in an online platform like Trinket and gotten an error like:

SyntaxError: no binding for nonlocal 'count' found

That’s because some environments:

  • Don’t support nonlocal well,
  • Or you’ve accidentally referenced a variable that’s not in the immediate outer scope.

✅ The Fix: Use a Mutable Object (like a list)

def outer():
    count = [0]

    def inner():
        count[0] += 1
        return count[0]

    return inner

Now:

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

Here, we store count in a list because lists are mutable — meaning we can update their contents without needing nonlocal.


🧃 Side Note: Reading vs Updating

def outer():
    name = "Ekene"

    def inner():
        return "Hello, " + name  # ✅ This is fine — no changes to `name`

    return inner

But if you try to change name:

def outer():
    name = "Ekene"

    def inner():
        name += " the Coder"  # ❌ Will throw an error
        return name

    return inner

Python thinks you’re creating a new local variable, and you get:

UnboundLocalError: local variable 'name' referenced before assignment

📌 Why nonlocal Is Important in Closures

✅ What nonlocal does:

  • It allows the inner function to modify variables from the outer function.
  • Without it, you can’t update outer variables — only read them.

Without nonlocal:

def outer():
    count = 0

    def inner():
        count += 1  # ❌ This fails without `nonlocal`
        return count

    return inner

With nonlocal:

def outer():
    count = 0

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

    return inner

📝 Practice Questions

  1. In your own words, what is a closure?

  2. True or False: A closure can remember variables from the function it was created inside.

  3. What does this code print?

    def outer():
        name = "Ekene"
        def greet():
            return "Hello, " + name
        return greet
    
    my_greet = outer()
    print(my_greet())
    
  4. Write a function called create_timer() that returns a function which adds 1 second each time it’s called — and works without nonlocal.

  5. Why is nonlocal important in closures? What happens if you leave it out?


<
Previous Post
🧭 JavaScript Navigator Object: Your JavaScript Passport to the Browser
>
Next Post
🚀JavaScript BOM (Browser Object Model): Your JavaScript Spaceship Dashboard