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