UnboundLocalError: local variable referenced before assignment in python closure
Question: I implemented two simple closures in Python. To me, they looks the same, but
one works and the other doesn't.

The working one is:

    
    
    def makeInc(x, y):
        def inc():
            return y + x
        return inc
    
    inc5 = makeInc(5, 10)
    inc10 = makeInc(10, 5)
    
    inc5 () # returns 15
    inc10() # returns 15
    

But the second one doesn't work:

    
    
    import os
    def linker(dest, filename):
        print filename
        def link(): 
            if os.path.isfile(filename): # line 17
                filename = os.path.join(os.getcwd(), filename)
                dest = os.path.join(dest, filename)
                y = rawinput('[y]/n: ln -sf %s %s' % (dest, filename))
                if y == 'n':
                    return 1
                else:
                    return os.system('ln -sf %s %s' %(dest, filename))
            else:
                return -1
        return link
    
    l = linker('~', '.vimrc')
    l()  # line 30
    

It faults at the first line of `link()` when executing `l()`:

    
    
    Traceback (most recent call last):
      File "test.py", line 30, in <module>
        l()
      File "test.py", line 17, in link
        if os.path.isfile(filename):
    UnboundLocalError: local variable 'filename' referenced before assignment
    

They seem identical to me so I don't understand why the second one doesn't
work. Any idea?


Answer: You have overwritten the variable with `filename = os.path.join(os.getcwd(),
filename)`, if you change the `filename =` to something other than `filename`
you won't get a `local variable 'filename' referenced before assignment`
error.

Once you set `filename =` you are no longer referring to the parameter
`filename` that is passed in you are referring to the local `filename` in the
scope of the inner function which you try to use in the if **before** you have
it defined.

You will have the same problem with dest, if you change the two lines and the
other variables to something like:

    
    
    filename_ = os.path.join(os.getcwd(), filename)
    dest_ = os.path.join(dest, filename)
    

You will see the code runs fine as filename now refers to the parameter not to
a local variable defined in your inner function.

You will see the exact same behaviour if you try to reassign `x` in your first
function and try to access `x` before you have defined it:

    
    
    def makeInc(x, y):
        def inc():
            print  y + x # will cause referenced before assignment error
            x = 5 # now x is local to the inner func, the x from the outer function is overridden
            return y + x
        return inc
    

If you print the `__closure__` attribute you will see what happens:

    
    
    def makeInc(x, y):
        def inc():
            return y + x
        return inc
    
    inc5 = makeInc(5, 10)
    inc10 = makeInc(10, 5)
    print(inc5.__closure__)
    (<cell at 0x7f180df67e50: int object at 0xef00f8>, <cell at 0x7f180df67fa0: int object at 0xef0080>)
    

Now reassigning x:

    
    
    def makeInc(x, y):
        def inc():
            print  y + x
            x= 5
            return y + x
        return inc
    
    inc5 = makeInc(5, 10)
    inc10 = makeInc(10, 5)
    print(inc5.__closure__)
    (<cell at 0x7fea11889fd8: int object at 0x291e080>,)
    

After reassigning in the inner function, there is no longer a reference to
`x`.

So basically the fundamental difference between your two original functions is
that in one you are reassigning the variable in the local scope and in the
other you are not. As you can see from the code above if you do something
similar in the first function the outcome is exactly the same.

There is a nice tut
[here](http://nbviewer.ipython.org/github/rasbt/python_reference/blob/master/tutorials/scope_resolution_legb_rule.ipynb#section_1)
on scopes LEGB etc..

