Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Considering that Python is an "interpreted" language, one naturally assumes that if a variable is already defined in an outer scope that same variable should still be accessible in the inner scope. And indeed in your first example when the inner <code>_func</code> merely prints <code>x</code> it works.</p> <p>The thing that's non-obvious about Python though is that this is not exactly how the scope of a variable is determined. Python analyzes at <em>compile</em> time which variables should be considered "local" to a scope based on whether they're assigned to within that scope. In this case assignment includes augmented assignment operators. So when Python compiles your inner <code>_func</code> in the second example to bytecode it sees the <code>x += 1</code> and determines that <code>x</code> must be a local variable to <code>_func</code>. Except of course since its first assignment is an augmented assignment there is no <code>x</code> variable locally to augment and you get the <code>UnboundLocalError</code>.</p> <p>A different way to see this might be to write something like:</p> <pre><code>def _func(): print x x = 2 </code></pre> <p>Here again because <code>_func</code> contains the line <code>x = 2</code> it will treat <code>x</code> as a local variable in the scope of that function and <em>not</em> as the <code>x</code> defined in the outer function. So the <code>print x</code> should also result in an <code>UnboundLocalError</code>.</p> <p>You can examine this in deeper detail by using the <a href="https://docs.python.org/2/library/dis.html" rel="nofollow"><code>dis</code></a> module to display the bytecode generated for the function:</p> <pre><code>&gt;&gt;&gt; dis.dis(_func) 2 0 LOAD_FAST 0 (x) 3 PRINT_ITEM 4 PRINT_NEWLINE 3 5 LOAD_CONST 1 (2) 8 STORE_FAST 0 (x) 11 LOAD_CONST 0 (None) 14 RETURN_VALUE </code></pre> <p>The <code>LOAD_FAST</code> opcode is for intended for "fast" lookups of local variables that bypasses slower, more general name lookups. It uses an array of pointers where each local variable (in the current stack frame) is associated with an index in that array, rather than going through dictionary lookups and such. In the above example the sole argument to the <code>LOAD_FAST</code> opcode is <code>0</code>--in this case the first (and only) local.</p> <p>You can check on the function itself (specifically its underlying code object) that there is one local variable used in that code, and that the variable name associated with it is <code>'x'</code>:</p> <pre><code>&gt;&gt;&gt; _func.__code__.co_nlocals 1 &gt;&gt;&gt; _func.__code__.co_varnames ('x',) </code></pre> <p>That's how <code>dis.dis</code> is able to report <code>0 LOAD_FAST 0 (x)</code>. Likewise for the <code>STORE_FAST</code> opcode later on.</p> <p>None of this is necessary to know in order to understand variable scopes in Python, but it can be helpful nonetheless to know what's going on under the hood.</p> <p>As already mentioned in some other answers, Python 3 introduced the <code>nonlocal</code> keyword which prevents this compile-time binding of names to local variables based on assignment to that variable in the local scope.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload