Paddy wrote: > Hi, > I am trying to work out why I get UnboundLocalError when accessing an > int from a function where the int is at the global scope, without > explicitly declaring it as global but not when accessing a list in > similar circumstances. > > The documentation: http://docs.python.org/ref/naming.html does not give > me enough info to determine why the difference exists as it does not > seem to mention types at all.. > > The code: > > ===== scope_and_type.py ======= > m = 0 > n = [0] > > def int_access0(): > m = m + 1 > return m > def int_access1(): > m += 1 > return m > def list_access0(): > n[0] = n[0] + 1 > return n > def list_access1(): > n[0] += 1 > return n > > try: > print "\nint_access0:", int_access0() > except UnboundLocalError, inst: > print " ERROR:\n", inst > try: > print "\nint_access1:", int_access1() > except UnboundLocalError, inst: > print " ERROR:\n", inst > try: > print "\nlist_access0:", list_access0() > except UnboundLocalError, inst: > print " ERROR:\n", inst > try: > print "\nlist_access1:", list_access1() > except UnboundLocalError, inst: > print " ERROR:\n", inst > > > print "\n (m,n) = ", (m,n) > > > p = (0,) > def tuple_access(): > return p[0] > try: > print "\ntuple_acces:", tuple_access() > except UnboundLocalError, inst: > print " ERROR:\n", inst > print "\n p = ", p > > ===== END scope_and_type.py ======= > > The output: > >>> > int_access0: ERROR: > local variable 'm' referenced before assignment > > int_access1: ERROR: > local variable 'm' referenced before assignment > > list_access0: [1] > > list_access1: [2] > > (m,n) = (0, [2]) > > tuple_acces: 0 > > p = (0,) > >>>
I blogged the following as a summary: (From: http://paddy3118.blogspot.com/2006/07/python-functions-assignments-and-scope.html) Python Functions: Assignments And Scope Explaining why this works: n = [0] def list_access(): n[0] = n[0] + 1 return n try: print "\nlist_access:", list_access() except UnboundLocalError, inst: print " ERROR:\n", inst And this throws the exception: m = 0 def int_access(): m = m + 1 return m try: print "\nint_access:", int_access() except UnboundLocalError, inst: print " ERROR:\n", inst To execute a source program, the Python compiler compiles your original source into 'byte codes' - a form of your program that is easier for the Python interpreter to later run. In generating this byte code, the byte code compiler will determine which variable names in a function are local to that function, (so alowing it to optimise accesses to such local names). The rule for determining if a variable is local to a function is: * If there is a global statement for the name in the function then the name is accessed from the global scope. * If there is no global statement for the name, and if there are assignments to the 'bare' name within the function then the name is of local scope. ( A bare name assignment means assignment to a name, where the name occurs without attribute references, subscripts, or slicing s, just the bare name). * Otherwise the name will be looked up in reverse order of all enclosing scopes, until it is found. In the second example, function int_access; name m is flagged as local by the byte code compiler as the bare name is being assigned to. The interpreter therefore looks for a value of m to increment only in the local scope, cannot find a value, then raises the UnboundLocalError exception. In function list_access, the bare name n is not assigned to, so n is found when looking back through enclosing scopes. References 1. http://groups.google.com/group/comp.lang.python/browse_frm/thread/db9955da70c4e0ca 2. http://pyref.infogami.com/assignments 3. http://pyref.infogami.com/naming-and-binding 4. http://www.python.org/doc/2.4/ref/global.html END. -- http://mail.python.org/mailman/listinfo/python-list