<p>您可以从<code>a</code>的作用域中了解<code>b</code>对自由变量(可用于绑定)的了解,如下所示:</p>
<pre><code>import inspect
print( "let's begin" )
def a():
if False:
x = 10
def b():
print(inspect.currentframe().f_code.co_freevars)
nonlocal x
x = 20
b()
a()
</code></pre>
<p>它给出了:</p>
^{pr2}$
<p>如果您注释掉<code>nonlocal</code>行,并删除<code>if</code>语句,其中包含<code>x</code>,您将看到<code>b</code>可用的自由变量只是<code>()</code>。在</p>
<p>让我们看看这生成了什么字节码指令,通过将<code>a</code>的定义放入IPython,然后使用<code>dis.dis</code>:</p>
<pre><code>In [3]: import dis
In [4]: dis.dis(a)
5 0 LOAD_CLOSURE 0 (x)
2 BUILD_TUPLE 1
4 LOAD_CONST 1 (<code object b at 0x7efceaa256f0, file "<ipython-input-1-20ba94fb8214>", line 5>)
6 LOAD_CONST 2 ('a.<locals>.b')
8 MAKE_FUNCTION 8
10 STORE_FAST 0 (b)
10 12 LOAD_FAST 0 (b)
14 CALL_FUNCTION 0
16 POP_TOP
18 LOAD_CONST 0 (None)
20 RETURN_VALUE
</code></pre>
<p>那么让我们看看<a href="https://github.com/python/cpython/blob/1896793520a49a6f97ae360c0b288967e56b005e/Python/ceval.c#L2220" rel="nofollow noreferrer">how ^{<cd10>} is processed in ^{<cd11>}</a>。在</p>
<pre><code>TARGET(LOAD_CLOSURE) {
PyObject *cell = freevars[oparg];
Py_INCREF(cell);
PUSH(cell);
DISPATCH();
}
</code></pre>
<p>所以我们看到它必须从封闭作用域的<code>x</code>查找<code>x</code>。在</p>
<p>这里提到的是<a href="https://docs.python.org/3/reference/executionmodel.html#resolution-of-names" rel="nofollow noreferrer">in the Execution Model documentation</a>,它说:</p>
<blockquote>
<p>The nonlocal statement causes corresponding names to refer to previously bound variables in the nearest enclosing function scope. SyntaxError is raised <strong>at compile time</strong> if the given name does not exist in any enclosing function scope.</p>
</blockquote>