proc A def/calls proc B: variable scoping rules.

Steven D'Aprano steve at REMOVEME.cybersource.com.au
Tue Aug 15 23:54:22 EDT 2006


On Tue, 15 Aug 2006 18:38:49 -0700, NevilleDNZ wrote:

> UnboundLocalError: local variable 'x2' referenced before assignment
> 
> I guess it is something to do with the scoping of duck typing.

Er, no. Scoping and duck typing are completely different concepts.

Scoping refers to the idea of where a variable name is valid.

Duck typing refers to the concept that one should not explicitly test for
the type of objects (the variable's content), but should rely on the
object being able to handle the methods you call ("if it quacks like a
duck, and swims like a duck, we can treat it as if it were a duck; if an
object contains the same methods as a string, we should treat it as if it
were a string").

The two concepts are unrelated.

You're error is precisely what the exception says: according to Python's
scoping rules, x2 is a local variable, but you've tried to read the value
of that name before setting it.

> I WAS expecting that the A.x2 was visable until x2 is somehow (by
> assignment) made local.

You expected wrong.

Here's some sample code that shows the scoping rules in action:


# scope.py
# globals
a, b, c = "global a", "global b", "global c"

def func0():
    print "    ", a, b, c

def func1():
    # define only a as a local variable
    a = "local a in func1"
    print "    ", a, b, c


def func2():
    # define both a and b as locals
    a = "local a in func2"
    b = "local b in func2"
    print "    ", a, b, c

def func3():
    # define a as a local, but in the wrong place
    try:
        print "    ", a, b, c
    except UnboundLocalError:
        print "Attempt to access the value of a local " \
        "variable before setting it."
    a = "local a in func3"
    print "    ", a, b, c

def func4():
    # uses nested functions
    a = "local a in func4"
    print "    ", a, b, c

    def func5():
        b = "local b in func5"
        print "Calling nested function func5:"
        print "    ", a, b, c

    def func6():
        global a, b
        print "Calling nested function func6:"
        print "    ", a, b, c

    func5()
    func6()

for function in (func0, func1, func2, func3, func4):
    print "Calling function %s:" % function.__name__
    function()

# end scope.py

Basically, when you access a variable name on the left hand side of an
assignment (e.g. "a = 1") ANYWHERE in a function, that name is local to
that function UNLESS it has been declared global.

When you access a variable name as the right hand side of an assignment,
or as an expression (e.g. "print a"), Python searches for it following the
scoping rules: first it searches for it in the function's local variables,
then the local variables of the next higher scope, and so on, and finally
it searches for it amongst the globals (which is the top-level scope of
everything).

Play around with the code and see if it makes sense.



-- 
Steven D'Aprano 




More information about the Python-list mailing list