<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>闭包</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>,都会创建一个小表来跟踪其中的绑定;i、 它说,“在这个范围内,<code>value</code>标识符指向传递的东西。”这个范围在函数执行结束时消失,除非有理由让它挂起</p>
<p>如果您从作用域内返回函数,这就是“作用域表”的一部分挂起的一个很好的原因——您要返回的函数可以在稍后调用它时引用该作用域表中的内容。因此,当在<code>get_fun</code>中创建<code>fun</code>时,Python会告诉<code>fun</code>关于<code>get_fun</code>的作用域表,该表在需要时随时可用</p>
<p>你可以在<a href="http://docs.python.org/reference/executionmodel.html" rel="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>