1

Could anyone explain the exception the below code. It only works when I change the var sub in the display() to another name. There is no global variable sub as well. So what happened ?

def sub(a, b):
    return a - b

def display():
    sub = sub(2,1) // if change to sub1 or sth different to sub, it works
    print sub
Hoan Dang
  • 2,222
  • 5
  • 27
  • 36

4 Answers4

2

Any variable you assign to inside a scope is treated as a local variable (unless you declare it global, or, in python3, nonlocal), which means it is not looked up in the surrounding scopes.

A simplified example with the same error:

def a(): pass

def b(): a = a()

Now, consider the different scopes involved here:

The global namespace contains a and b.

The function a contains no local variables.

The function b contains an assignment to a - this means it is interpreted as a local variable and shadows the function a from the outer scope (in this case, the global scope). As a has not been defined inside of b before the call, it is an unbound local variable, hence the UnboundLocalError. This is exactly the same as if you had written this:

def b(): x = x()

The solution to this is simple: choose a different name for the result of the sub call.

It is important to note that the order of use and assignment makes no difference - the error would have still happened if you wrote the function like this:

def display():
    value = sub(2,1)         #UnboundLocalError here...
    print value
    sub = "someOtherValue"   #because you assign a variable named `sub` here

This is because the list of local variables is generated when the python interpreter creates the function object.

l4mpi
  • 5,103
  • 3
  • 34
  • 54
  • so the unbound error comes from the call to the function because it is first shadowed by the previous assignement? is it the same if x (local variable) is assigned to any value, and then x (function) is called ? – njzk2 Oct 01 '12 at 12:57
  • The error is that the your function contains an assignment to `sub` so sub is treated as a local variable. And you try to use this local variable during the initial assignment while it doesn't have a value yet. – l4mpi Oct 01 '12 at 13:09
1

This was originally a comment. The OP found this useful as an answer. Therefore, I am re-posting it as an answer

Initially, sub is a function. Then, it becomes the return value of a function. So when you say print sub, python doesn't know which sub you are referring to.

Edit:

First you define a function sub. Now, python knows what sub is.

When you create a variable and try to assign to it (say x = 2), python evaluates the stuff on the right hand side of the = and assigns the value of the evaluation as the value of the stuff on the left hand side of the =. Thus, everything on the right hand side should actually compute.

So if your statement was x = x+1, then x better have a value assigned to it before that line; and the previously defined x has to be of some type compatible with the addition of 1.

But suppose x is a function, and you make a variable called x in some other function, and try to assign to it, a value computed with function x, then this really starts to confuse python about which x you are referring to. This is really an oversimplification of this answer, which does a much better job of explaining variable scope and shadowing in python functions

Community
  • 1
  • 1
inspectorG4dget
  • 110,290
  • 27
  • 149
  • 241
  • 3
    This is overly simplified - if you said `sub = 1` inside `display` you still shadow the function name, which is perfectly legal. The problem is that the name is *used* and *assigned to* in the same scope. See [this answer](http://stackoverflow.com/a/12092094/1110381) for a more detailed explanation of closures in python. – l4mpi Oct 01 '12 at 12:30
  • @l4mpi: fair enough. I really should stop answering questions on Monday mornings before my coffee kicks in. Thank you for the clarification – inspectorG4dget Oct 01 '12 at 12:57
1

For every variable used, Python determines whether it is a local or a nonlocal variable. Referencing a unknown variable marks it as nonlocal. Reusing the same name as a local variable later is considered a programmers mistake.

Consider this example:

def err():
    print x # this line references x
    x = 3   # this line creates a local variable x
err()

This gives you

Traceback (most recent call last):
  File "asd.py", line 5, in <module>
    err()
  File "asd.py", line 2, in err
    print x # this line references x
UnboundLocalError: local variable 'x' referenced before assignment

What happens is basically that Python keeps track of all references to names in code. When it reads the line print x Python knows that x is a variable from a outer scope (upvalue or global). However, in x = 3 the x is used as a local variable. As this is a inconsistency in the code, Python raises an UnboundLocalError to get the Programmers attention.

Jochen Ritzel
  • 104,512
  • 31
  • 200
  • 194
-1

Python start executing your code and get the function first

def sub(a, b):
    return a - b

So after executing this interpreter get the sub as a function. Now when come to next line it found

def display():
    sub = sub(2,1) // if change to sub1 or sth different to sub, it works
    print sub

so first line sub = sub (2, 1) will convert the sub function to sub variable. From this function you are returning the sub variable. So its create problem.

Nilesh
  • 20,521
  • 16
  • 92
  • 148