Python Unbound Local Variable Referenced Before Assignment

UnboundLocalError: local variable referenced before assignment

So that sucks

Howdya fix that?

I’ll tell you. First, a simple example of the problem:

#This is valid python 2.5 code #My global variable: USER_COUNT = 0 #functions: def Main(): AddUser() def AddUser(): print 'There are',USER_COUNT,'users so far' # actually run Main() Main()

^ That program WORKS FINE. Function AddUser() just references the USER_COUNT variable, which was declared as a global (outside of any of the function blocks).

Here’s where it goes wrong: when we try to write to or we try to update the value of the global variable

#USER_COUNT is a GLOBAL variable USER_COUNT = 0 def Main(): AddUser() def AddUser(): USER_COUNT = USER_COUNT + 1 print 'There are',USER_COUNT,'users so far' Main()

Then we get: UnboundLocalError: local variable ‘USER_COUNT’ referenced before assignment

So that sucks.

The reason this happens is because AS SOON AS YOU WRITE TO A VARIABLE, that variable is AUTOMATICALLY considered LOCAL to the function block in which its declared. Namely:

#USER_COUNT is a GLOBAL! USER_COUNT = 0 def AddUser(): USER_COUNT = USER_COUNT + 1 print 'There are',USER_COUNT,'users so far'

EVEN THOUGH we declared USER_COUNT as a GLOBAL, the simple act of WRITING TO IT __ANYWHERE__ in the function scuzzles-up the “globalness” of the USER_COUNT variable, and like, automatically makes ANY use of USER_COUNT refer to a LOCAL VARIABLE inside of AddUser().

So howdya fix it?

Easy! You do this:

#global USER_COUNT = 0 def Main(): AddUser() def AddUser(): global USER_COUNT ######!!! IMPORTANT !!! Make sure # to use the GLOBAL version of USER_COUNT, not some # locally defined copy of that. I think this # might be a python feature to stop functions from # clobbering the global variables in a program USER_COUNT = USER_COUNT + 1 print 'There are',USER_COUNT,'users so far' Main()

This is an ok-nice feature that might stop a program’s functions from clobbering the globals (since you really have this “just use it” attitude to a variable and you may have no clue that you’re clobbering a global), but really it might be nice if python were more consistent and required use of this global thing for BOTH read/write. Though I guess it could be kinda convenient behavior .. I don’t know yet, haven’t programmed in python for long enough.

Like this:

LikeLoading...

Related

The OP wrote (emphasis mine):

The answer should be 2 because first the main() function is called, then the first() function is called, overriding the global variable.

It is not overriding the global variable. Unless you explicitly specify a variable as global, if there is any assignment to the variable in a function, it is assumed to be local. See also the python tutorial on defining functions where it states (emphasis mine):

More precisely, all variable assignments in a function store the value in the local symbol table; whereas variable references first look in the local symbol table, then in the local symbol tables of enclosing functions, then in the global symbol table, and finally in the table of built-in names. Thus, global variables cannot be directly assigned a value within a function (unless named in a global statement), although they may be referenced.

and the documentation of the statement (if anyone using Python 3 is looking at this, please also take a look at the (compared to ) very useful statement and its PEP 3104).

To "fix" your code:

Do not use global variables in this way please. @LutzHorn has shown in his answer how to do it right.

The reason to avoid global variables is that their effect is hard to test for, and as soon as code gets complex enough, hard to reason about. If every function modifies global variables instead of properly taking parameters and returning values, understanding what the code actually does is hard as soon as one has more than a week or so of distance from it.

0 thoughts on “Python Unbound Local Variable Referenced Before Assignment

Leave a Reply

Your email address will not be published. Required fields are marked *