Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

local/global variable confusion in python [duplicate]

Tags:

python

Possible Duplicate:
referenced before assignment error in python

I'm getting a strange error in python. The following ipython log sums it up:

In [10]: def confused(stuff):
   ....:     print huh
   ....:     return stuff
   ....: 

In [11]: confused(87)
0
Out[11]: 87

In [12]: def confused(stuff):
   ....:     print huh
   ....:     huh += 1
   ....:     return stuff
   ....: 

In [13]: confused(9)
---------------------------------------------------------------------------
UnboundLocalError                         Traceback (most recent call last)
/home/max/verk/btr-email/build/x86_64/bin/ipython in <module>()
----> 1 confused(9)

/home/max/verk/btr-email/build/x86_64/bin/ipython in confused(stuff)
      1 def confused(stuff):
----> 2     print huh
      3     huh += 1
      4     return stuff

UnboundLocalError: local variable 'huh' referenced before assignment

The only difference between the function that works and the one that throws an error is the +=1 line, and even then, it throws an error on a line which was previously working! It also doesn't throw an error if I put global huh before referencing huh in the 2nd version of the method.

Why does adding a line where I add one to the variable suddenly change it from a global to a local variable?

like image 441
mavix Avatar asked Oct 19 '25 18:10

mavix


1 Answers

In your script, huh refers to a global variable. You can't change the reference to a global variable in a function without explicitly telling python that is what you want to do:

def confused(stuff):
    global huh
    print huh
    huh += 1
    return stuff

For immutable objects like ints, strings, floats, etc, that means that you can't make any changes to the object without declaring it as global. For mutable objects, you can make changes to the objects items or attributes, but you still can't change the object's reference.


This is all a question of scope. since huh isn't in the local scope of confused, python finds it in the global scope. Since it is found in the global scope, you can't assign to it unless you specifically say that you want to (using global as I have done above). However, if it's a list, once the list is found, you have access to all of that list's methods (including __setitem__, append, etc.)


As to the location of the error, this can be cleared up with a little disassembling:

>>> def confused(stuff):
...    print huh
... 

>>> import dis
>>> dis.dis(confused)
  2           0 LOAD_GLOBAL              0 (huh)
              3 PRINT_ITEM          
              4 PRINT_NEWLINE       
              5 LOAD_CONST               0 (None)
              8 RETURN_VALUE

>>> def confused2(stuff):
...    print huh
...    huh += 1
... 

>>> dis.dis(confused2)
  2           0 LOAD_FAST                1 (huh)
              3 PRINT_ITEM          
              4 PRINT_NEWLINE       

  3           5 LOAD_FAST                1 (huh)
              8 LOAD_CONST               1 (1)
             11 INPLACE_ADD         
             12 STORE_FAST               1 (huh)
             15 LOAD_CONST               0 (None)
             18 RETURN_VALUE   

You can see that in confused2, python is already trying to LOAD_FAST (meaning, look for a local variable) at the first line of the function. However, no local variable huh exists hence the Exception.

like image 157
mgilson Avatar answered Oct 22 '25 08:10

mgilson



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!