denniss
denniss

Reputation: 17589

Python's closure - local variable referenced before assignment

I am trying to understand how closure works in Python.

I feel like add1 should work just fine here. I would expect the variable x to have been defined when helper is called. However, it is giving me a Local variable referenced before assignment error.

add2 is very similar to add1. Instead of assigning x with an integer, it assigns it with a dictionary. The behavior of it is also aligned with what I would expect. x is defined and reference-able inside helper.

import random

def add1():
    x = 0
    def helper():
        x = x + 1
        return x
    return helper

def add2():
    x = {}
    def helper():
        x[random.randint(1,1000)] = 3
        return x
    return helper

if __name__ == '__main__':
    a1 = add1()
    a2 = add2()

    # print(a1()) #This causes error
    print(a2()) #{650: 3}
    print(a2()) #{650: 3, 333: 3}

What's the logic behind this? What am I doing differently other than that the types of x are different?

Upvotes: 23

Views: 5560

Answers (1)

Ignacio Vazquez-Abrams
Ignacio Vazquez-Abrams

Reputation: 798606

You're expecting the compiler to know that the variable has been bound outside the closure. This is not true, and hence you need to use nonlocal to indicate this.

def add1():
    x = 0
    def helper():
        nonlocal x
        x = x + 1
        return x
    return helper

EDIT By denniss:

nonlocal is not necessary in add2 because it's just modifying x and not re-binding it (aka not re-assigning it). Whereas in add1, x= x+1 is a re-assignment.

Upvotes: 46

Related Questions