Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python's closure - local variable referenced before assignment

Tags:

python

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?

like image 905
denniss Avatar asked Apr 27 '16 22:04

denniss


People also ask

How do I fix local variables before assignment in Python?

The Python "UnboundLocalError: Local variable referenced before assignment" occurs when we reference a local variable before assigning a value to it in a function. To solve the error, mark the variable as global in the function definition, e.g. global my_var .

How do you fix UnboundLocalError?

UnboundLocalError can be solved by changing the scope of the variable which is complaining. You need to explicitly declare the variable global. Variable x's scope in function printx is global. You can verify the same by printing the value of x in terminal and it will be 6.

Are closures Pythonic?

Closures are elegant Python constructs. In this article, we'll learn about them, how to define a closure, why and when to use them. But before getting into what a closure is, we have to first understand what a nested function is and how scoping rules work for them.

What is an UnboundLocalError?

The UnboundLocalError: local variable referenced before assignment error is raised when you try to assign a value to a local variable before it has been declared. You can solve this error by ensuring that a local variable is declared before you assign it a value.


1 Answers

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.

like image 104
Ignacio Vazquez-Abrams Avatar answered Sep 19 '22 17:09

Ignacio Vazquez-Abrams