Unbound name showing up in stack frame using inspect module
<p>I recently ran into a bug that was quite difficult to track down. I had accidentally re-used a class name as a variable (see code below), so when I tried to call the class I (understandably) got an error. The reason it was so hard to track down is that my debugger (Wing IDE 5.1.10) would execute the line successfully in the debug probe, but when I tried to run the same line in the interpreter it errored out. On further investigation, I found that when I examined the frame data using the inspect module, the name was still shown as a global variable bound to my class. So, I was mystified at receiving a UnboundLocalError on a name that was clearly defined and bound in my frame.</p>

<p>This reproduces the issue:</p>

<pre><code>import inspect

class MyClass(object):
    def __init__(self):
        print "MyClass init() method called successfully"

def newscope():

    #MyClass is not in the current frame's locals:
    assert 'MyClass' not in inspect.currentframe().f_locals.keys()

    #MyClass is in the current frame's globals and can be called successfully:
    class_object = inspect.currentframe().f_globals['MyClass']
    print class_object
    class_object()

    #But, calling MyClass by name results in UnboundLocalError: local
    #variable 'MyClass' referenced before assignment:
    print MyClass

    #Strangely, if at this point I go into the debug probe and run the same
    #line (print MyClass) it executes successfully, printing 
    #"&lt;class '__main__.MyClass'&gt;"

    #Re-assigning the name MyClass is what causes the UnboundLocalError:
    MyClass = 5

if __name__ == '__main__':
    newscope()
</code></pre>

<p>Results:</p>

<pre><code>&lt;class '__main__.MyClass'&gt;
MyClass init() method called successfully
Traceback (most recent call last):
  Python Shell, prompt 1, line 29
  Python Shell, prompt 1, line 19
UnboundLocalError: local variable 'MyClass' referenced before assignment
</code></pre>

<p>Again, I understand why I am getting the UnboundLocalError. What I don't understand is why the inspect module is still showing the name as being bound to the class object when clearly that isn't the case. Am I missing something, or is this a bug in the inspect module?</p>

<p>I'm running python 2.7.11.</p>

<p>If a value is assigned to a variable within a function, that variable becomes a local variable within that function.</p>

<p>That variable is treated as local from the moment the function is created, i.e. before it is called for the first time. Python actually optimizes access to local variables and does not make a lookup into the locals() dictionary, but "knows" exactly where to find each local variable (see <a href="http://stackoverflow.com/a/11242447/389289">this answer about performance within a function</a>).</p>

<p>So, the fact that this assignemt is done at the end of the function does not make a difference. Within your function <code>newscope</code>, variable <code>MyClass</code> is a local variable. Assigning to the <code>MyClass</code> variable after using it is actually what causes the <code>UnboundLocalError</code> in this example.</p>

<p>Take a simpler example:</p>

<pre><code>a = 4

def global_a_example():
    print a   # a is a global variable: prints 4

def local_a_example():
    a = 5
    print a   # a is a local variable: prints 5

def unbound_local_a_example():
    print a   # a is a local variable, but not initialized: raises UnboundLocalError
    a = 5
</code></pre>

<p><strong>EDIT:</strong> explanation why it looks like the variable is bound</p>

<p>Note that the unbound locals do not end up in the locals dict. That is not because they are not locals. It is because they are unbound. See the following example:</p>

<pre><code>a = 1
b = 2

def f():
    assert 'a' in globals()    # of course
    assert 'a' not in locals() # local 'a' has not been initialized and has no value
    assert 'a' in f.__code__.co_varnames # 'a' is local nevertheless!
    assert 'b' not in f.__code__.co_varnames # 'b' is not local...

    # a != 1 test would raise and exception here because 'a' is local and uninitialized

    a = 10                     # initialize local 'a' (and store it in locals)

    assert 'a' in globals()    # it is still in globals, yes
    assert 'a' in locals()     # it is also in locals

    assert globals()['a'] == 1 # global 'a' has value 1
    assert locals()['a'] == 2  # local 'a' has value 2
    assert a == 10             # a is local 'a'!
    assert b == 2              # b is global 'b'

# but you don't even have to call f()!!!
# 'a' is already defined to be a local variable in f, see:

print f.__code__.co_varnames # prints ('a',)
</code></pre>

<p>So, 'a' is not bound until written to. It is a key in the globals dict, but that is irrelevant. It is not used from that dict, because it is defined to be local.</p>

python stack-trace