Scope, type and UnboundLocalError

Paddy paddy3118 at netscape.net
Thu Jul 27 02:00:11 EDT 2006


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.




More information about the Python-list mailing list