Skip to main content

How to Define a Closure that Increments and Decrements Values in Python

In Python, a closure is a function object that remembers values in enclosing scopes even if they are not present in memory. This feature allows you to create function-based objects that maintain internal state (like a counter) without writing a full class.

This guide explains how to create a closure that can perform multiple actions, specifically incrementing and decrementing a value, by utilizing the nonlocal keyword and returning multiple inner functions.

Understanding Scope and the nonlocal Keyword

To modify a variable from an outer (enclosing) function inside an inner function, you must explicitly declare it as nonlocal. Without this, Python treats the variable as local to the inner function, leading to errors when you try to modify immutable types like integers.

The Common Mistake

Attempting to modify a variable from the outer scope without nonlocal causes an UnboundLocalError.

def make_counter():
count = 0

def increment():
# ⛔️ Error: Python tries to create a new local variable 'count'
# but fails because we reference it before assignment (count + 1)
count += 1
return count

return increment

try:
counter = make_counter()
counter()
except UnboundLocalError as e:
print(f"Error: {e}")

Output:

Error: cannot access local variable 'count' where it is not associated with a value
note

In this code, the error occurs because Python interprets count as a local variable inside the increment function. Since you attempt to modify it (count += 1) without initializing it first, Python cannot access the variable, leading to the error.

Solution

Use nonlocal to tell Python that count belongs to the enclosing scope.

def make_counter():
count = 0

def increment():
# ✅ Correct: Explicitly references the outer variable
nonlocal count
count += 1
return count

return increment

counter = make_counter()
print(f"Count: {counter()}")

Output:

Count: 1

Method 1: Returning a Tuple of Functions

To support both incrementing and decrementing, the outer function needs to define two inner functions and return them both. Returning them as a tuple allows you to unpack them easily.

def create_counter(initial_value=0):
# This variable is the 'state' shared by both inner functions
value = initial_value

def inc():
nonlocal value
value += 1
return value

def dec():
nonlocal value
value -= 1
return value

# Return both functions
return inc, dec

# ✅ Usage: Unpack the returned tuple into two variables
increment, decrement = create_counter(10)

print(f"Increment: {increment()}") # 10 + 1
print(f"Increment: {increment()}") # 11 + 1
print(f"Decrement: {decrement()}") # 12 - 1

Output:

Increment: 11
Increment: 12
Decrement: 11
note

The variable value is hidden from the global scope. It can only be modified via the inc and dec functions, providing data encapsulation similar to a private class attribute.

Method 2: Returning a Dictionary of Functions

If you have multiple operations (increment, decrement, reset, get_current), returning a tuple becomes confusing because you have to remember the order of the functions. Returning a dictionary is more scalable and explicit.

def create_advanced_counter(start=0):
count = start

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

def down():
nonlocal count
count -= 1
return count

def reset():
nonlocal count
count = start
return count

# ✅ Return a dictionary for clear access
return {
'inc': up,
'dec': down,
'reset': reset
}

# Usage
actions = create_advanced_counter(5)

print(f"Up: {actions['inc']()}")
print(f"Up: {actions['inc']()}")
print(f"Down: {actions['dec']()}")
print(f"Reset: {actions['reset']()}")

Output:

Up:    6
Up: 7
Down: 6
Reset: 5

Closures vs. Classes

While closures are powerful, Python is an Object-Oriented language. It is often cleaner to use a Class for state management if the logic becomes complex.

When to use Closures:

  • You need a simple callback function with a tiny bit of state.
  • You want to hide data (encapsulation) strictly.
  • You want to avoid the boilerplate of class, self, and __init__.

When to use Classes:

  • You need to manage complex state.
  • You need inheritance or type checking.
  • You require more than 2-3 methods to manipulate the data.
# Class Equivalent of Method 1
class Counter:
def __init__(self, start=0):
self.value = start

def inc(self):
self.value += 1
return self.value

def dec(self):
self.value -= 1
return self.value

c = Counter(10)
print(f"Class Increment: {c.inc()}")

Output:

Class Increment: 11
tip

Closures are often faster to define and lighter in memory for very simple tasks, but Classes are generally more readable for large applications.

Conclusion

To define a closure that increments and decrements:

  1. Define an outer function that accepts an initial value.
  2. Define inner functions (inc, dec) that use the nonlocal keyword to modify the outer variable.
  3. Return the inner functions as a tuple or dictionary.
  4. Unpack or access these functions to manipulate the shared state.