[python] Don't understand why UnboundLocalError occurs (closure)

What am I doing wrong here?

counter = 0

def increment():
  counter += 1

increment()

The above code throws an UnboundLocalError.

This question is related to python scope closures global-variables

The answer is


To answer the question in your subject line,* yes, there are closures in Python, except they only apply inside a function, and also (in Python 2.x) they are read-only; you can't re-bind the name to a different object (though if the object is mutable, you can modify its contents). In Python 3.x, you can use the nonlocal keyword to modify a closure variable.

def incrementer():
    counter = 0
    def increment():
        nonlocal counter
        counter += 1
        return counter
    return increment

increment = incrementer()

increment()   # 1
increment()   # 2

* The question origially asked about closures in Python.



Python has lexical scoping by default, which means that although an enclosed scope can access values in its enclosing scope, it cannot modify them (unless they're declared global with the global keyword).

A closure binds values in the enclosing environment to names in the local environment. The local environment can then use the bound value, and even reassign that name to something else, but it can't modify the binding in the enclosing environment.

In your case you are trying to treat counter as a local variable rather than a bound value. Note that this code, which binds the value of x assigned in the enclosing environment, works fine:

>>> x = 1

>>> def f():
>>>  return x

>>> f()
1

try this

counter = 0

def increment():
  global counter
  counter += 1

increment()

You need to use the global statement so that you are modifying the global variable counter, instead of a local variable:

counter = 0

def increment():
  global counter
  counter += 1

increment()

If the enclosing scope that counter is defined in is not the global scope, on Python 3.x you could use the nonlocal statement. In the same situation on Python 2.x you would have no way to reassign to the nonlocal name counter, so you would need to make counter mutable and modify it:

counter = [0]

def increment():
  counter[0] += 1

increment()
print counter[0]  # prints '1'

To modify a global variable inside a function, you must use the global keyword.

When you try to do this without the line

global counter

inside of the definition of increment, a local variable named counter is created so as to keep you from mucking up the counter variable that the whole program may depend on.

Note that you only need to use global when you are modifying the variable; you could read counter from within increment without the need for the global statement.


The reason of why your code throws an UnboundLocalError is already well explained in other answers.

But it seems to me that you're trying to build something that works like itertools.count().

So why don't you try it out, and see if it suits your case:

>>> from itertools import count
>>> counter = count(0)
>>> counter
count(0)
>>> next(counter)
0
>>> counter
count(1)
>>> next(counter)
1
>>> counter
count(2)

Examples related to python

programming a servo thru a barometer Is there a way to view two blocks of code from the same file simultaneously in Sublime Text? python variable NameError Why my regexp for hyphenated words doesn't work? Comparing a variable with a string python not working when redirecting from bash script is it possible to add colors to python output? Get Public URL for File - Google Cloud Storage - App Engine (Python) Real time face detection OpenCV, Python xlrd.biffh.XLRDError: Excel xlsx file; not supported Could not load dynamic library 'cudart64_101.dll' on tensorflow CPU-only installation

Examples related to scope

Angular 2 - Using 'this' inside setTimeout Why Is `Export Default Const` invalid? How do I access previous promise results in a .then() chain? Problems with local variable scope. How to solve it? Why is it OK to return a 'vector' from a function? Uncaught TypeError: Cannot read property 'length' of undefined Setting dynamic scope variables in AngularJs - scope.<some_string> How to remove elements/nodes from angular.js array Limiting number of displayed results when using ngRepeat A variable modified inside a while loop is not remembered

Examples related to closures

Store a closure as a variable in Swift How to map to multiple elements with Java 8 streams? groovy: safely find a key in a map and return its value Exception: Serialization of 'Closure' is not allowed JavaScript closures vs. anonymous functions Don't understand why UnboundLocalError occurs (closure) Closure in Java 7 How should I call 3 functions in order to execute them one after the other? Why aren't python nested functions called closures? Passing parameters in Javascript onClick event

Examples related to global-variables

What is the best way to declare global variable in Vue.js? How do I turn off the mysql password validation? How to declare Global Variables in Excel VBA to be visible across the Workbook How to create a global variable? global variable for all controller and views How to define global variable in Google Apps Script How to modify a global variable within a function in bash? Using a global variable with a thread Is it possible to use global variables in Rust? How to access global js variable in AngularJS directive