Confused about nested scopes and when names get added to namespaces

Russell Warren russandheather at gmail.com
Wed Sep 8 17:18:52 EDT 2010


I'm having trouble understanding when variables are added to
namespaces.  I thought I understood it, but my nested function
examples below have me very confused.

In each test function below I have an x variable (so "x" is in the
namespace of each test function).  I also have a nested function in
each (innerFunc) that has different flavors of trying to access or
assign a variable named "x".

---
def test1():
    print "running test1..."
    x = 1
    def innerFunc():
        print "inner locals():",
        print "%s" % locals()  # x not present (yet)
        x = 2
        print x
    innerFunc()
    print "x left as %s\n" % x

def test2():
    print "running test2..."
    x = 1
    def innerFunc():
        print "inner locals():",
        print "%s" % locals()  # x not present
    innerFunc()
    print "x left as %s\n" % x

def test3():
    print "running test3..."
    x = 1
    def innerFunc():
        print "inner locals():",
        print "%s" % locals()  # how is x in locals in this case??
        print x
    innerFunc()
    print "x left as %s\n" % x

test1()
test2()
test3()

---

With the nested scope rules, I thought that *at the time of* trying to
access an object with a given name, if the name was not available in
the namespace of the local function python would then check the
namespace of the parent function.  My tests above don't seem to match
this.  Specifically my "at the time of" assumption.

What is happening in test3?  How is it that "x" ends up in the local
namespace before it is ever referenced?  It seems that, prior to
execution time, the python compiler is "magically" determining that
I'm referencing a particular name before assignment and shoving it
into the local namespace so it can be used.  I did not think the
compiler went into function bodies, aside from basic syntax checking.

Further confusing me (or confirming the compiler behavior) is adding a
4th test with only one added line...

def test4():
    print "running test4..."
    x = 1
    def innerFunc():
        print "inner locals():",
        print "%s" % locals()  # how is x in locals in this case??
        print x
        x = 2  #ONLY ADDED LINE TO TEST3
    innerFunc()
    print "x left as %s\n" % x

In this case I get "UnboundLocalError: local variable 'x' referenced
before assignment".  I think this means that the compiler (prior to
runtime) inspected the code, determined I will do an assignment,
decided _not_ to bring the parent's x into the local namespace, and as
a result caused the unbound name problem at runtime.

It seems that the parent's "x" is brought directly into the local
namespace (when appropriate), rather than the namespace lookup just
moving up the hierarchy when not found.  This is confusing to me and
is making me question my understanding of namespace lookups.  Are
nested scopes a special case where the lookup is handled differently?

What if I want to change the value of the parent's "x"?  test4 implies
that I can't.

Have I got this right?  Can someone please clarify what is going on?




More information about the Python-list mailing list