<p>当执行函数语句时,它们被绑定到它们的(词汇上的)封闭范围。</p>
<p>在您的代码片段中,lambda被绑定到全局作用域,因为<code>for</code>套件在Python中不是作为独立作用域单元执行的。在<code>for</code>循环的末尾,将<code>num</code>绑定到封闭作用域中。演示:</p>
<pre><code>for num in range(1, 6):
pass
assert num == 5 # num is now bound in the enclosing scope
</code></pre>
<p>因此,当您在<code>for</code>循环中绑定标识符时,实际上是在操作封闭作用域。</p>
<pre><code>for num in range(1, 6):
spam = 12
assert num == 5 # num is now bound in the enclosing scope
assert spam == 12 # spam is also bound in the enclosing scope
</code></pre>
<p>同样的清单理解:</p>
<pre><code>[num for num in range(1, 6)]
assert num == 5
</code></pre>
<p>我知道,这让我很兴奋。任何人,根据我们的新知识,我们可以确定您创建的lambda是指封闭作用域中绑定的(单个)<code>num</code>标识符。这应该更有意义:</p>
<pre><code>functions = []
for number in range(1, 6):
def fun():
return number
functions.append(fun)
assert all(fun() == 5 for fun in functions)
assert all(fun() is number for fun in functions)
</code></pre>
<p>下面是最酷的部分,更能说明这一点:</p>
<pre><code># Same as above -- commented out for emphasis.
#functions = []
#for number in range(1, 6):
# def fun():
# return number
# functions.append(fun)
#assert all(fun() == 5 for fun in functions)
#assert all(fun() is number for fun in functions)
number = 6 # Rebind 6 in the scope and see how it affects the results.
assert all(fun() == 6 for fun in functions)
</code></pre>
<p>因此,解决这个问题的方法当然是为每个要绑定的<code>number</code>创建一个新的封闭作用域。在Python中,可以使用模块、类和函数创建新的封闭作用域。通常只使用函数为另一个函数创建新的封闭作用域。</p>
<p>在Python中,闭包</em>是返回另一个函数的函数。有点像函数构造函数。在下面的示例中签出<code>get_fun</code>:</p>
<pre><code>def get_fun(value):
""":return: A function that returns :param:`value`."""
def fun(): # Bound to get_fun's scope
return value
return fun
functions = []
for number in range(1, 6):
functions.append(get_fun(number))
assert [fun() for fun in functions] == range(1, 6)
</code></pre>
<p>因为<code>get_fun</code>是一个函数,所以它有自己的内部作用域。每次用一个值调用<code>get_fun</code>时,都会创建一个小表来跟踪其中的绑定;也就是说,它会说:“在这个范围内,<code>value</code>标识符指向传递的内容。”这个范围在函数执行结束时消失,除非有理由让它挂起。</p>
<p>如果要从作用域内返回函数,这是“作用域表”的某些部分挂起的一个很好的原因——稍后调用时,要返回的函数可能会引用该作用域表中的内容。因此,当在<code>get_fun</code>中创建<code>fun</code>时,Python告诉<code>fun</code>有关<code>get_fun</code>的作用域表的信息,当需要时<code>fun</code>会很方便。</p>
<p>您可以在<a href="http://docs.python.org/reference/executionmodel.html" rel="nofollow noreferrer">Python docs on the execution model</a>中阅读更多关于详细信息和技术术语(我稍微软化了一下)。您还可以查看函数使用<code>print fun.__closure__</code>引用的封闭作用域部分。在上面,我们看到了对<code>value</code>的引用,它恰好是一个int:</p>
<pre><code># Same as before, commented out for emphasis.
#functions = []
#for number in range(1, 6):
# functions.append(get_fun(number))
#assert [fun() for fun in functions] == range(1, 6)
print functions[0].__closure__
# Produces: (<cell at 0x8dc30: int object at 0x1004188>,)
</code></pre>