<p>闭包单元格指的是函数所需的值,但这些值取自周围的范围。</p>
<p>当Python编译嵌套函数时,它会注意到它引用的任何变量,但这些变量仅在嵌套函数和父作用域的代码对象中的父函数(而不是全局)中定义。这些分别是这些函数的<code>__code__</code>对象上的<code>co_freevars</code>和<code>co_cellvars</code>属性。</p>
<p>然后,当实际<em>创建</em>嵌套函数(在执行父函数时发生)时,这些引用将用于将闭包附加到嵌套函数。</p>
<p>函数闭包包含一个单元元组,每个单元对应一个自由变量(在<code>co_freevars</code>中命名);单元是对父作用域的局部变量的特殊引用,它遵循这些局部变量指向的值。这最好用一个例子来说明:</p>
<pre><code>def foo():
def bar():
print(spam)
spam = 'ham'
bar()
spam = 'eggs'
bar()
return bar
b = foo()
b()
</code></pre>
<p>在上面的例子中,函数<code>bar</code>有一个闭包单元格,它指向函数<code>foo</code>中的<code>spam</code>。单元格遵循<code>spam</code>的值。更重要的是,一旦<code>foo()</code>完成并返回<code>bar</code>,即使<code>foo</code>中的变量<code>spam</code>不再存在,单元格仍继续引用该值(字符串<code>eggs</code>)。</p>
<p>因此,上述代码输出:</p>
<pre><code>>>> b=foo()
ham
eggs
>>> b()
eggs
</code></pre>
<p>而<code>b.__closure__[0].cell_contents</code>就是<code>'eggs'</code>。</p>
<p>注意,当<code>bar()</code>被调用</em>时,闭包会被取消引用;闭包不会在这里捕获值。当您生成引用循环变量的嵌套函数(使用<code>lambda</code>表达式或<code>def</code>语句)时,这会有所不同:</p>
<pre><code>def foo():
bar = []
for spam in ('ham', 'eggs', 'salad'):
bar.append(lambda: spam)
return bar
for bar in foo():
print bar()
</code></pre>
<p>上面将连续打印<code>salad</code>三次,因为所有三个<code>lambda</code>函数都引用<code>spam</code>变量,而不是创建函数对象时绑定到的值。当<code>for</code>循环结束时,<code>spam</code>已绑定到<code>'salad'</code>,因此所有三个闭包都将解析为该值。</p>