Skip to content

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

Learn how to create Python closures that increment and decrement values using the nonlocal keyword, returning functions as tuples or dictionaries for stateful operations.

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():
        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

Solution

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

def make_counter():
    count = 0
    
    def increment():
        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):
    value = initial_value

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

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

    return inc, dec

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

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 {
        'inc': up,
        'dec': down,
        'reset': reset
    }

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 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

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.
Navigation