当函数语句执行就必然要他们(词汇)封闭的范围。
在您的代码片段中,lambda表达式绑定到全局作用域,因为for
套件不作为Python中的独立作用域单元执行。在for
循环结束时,num
被绑定在封闭范围内。演示:
for num in range(1, 6):
pass
assert num == 5 # num is now bound in the enclosing scope
因此,当您在for
循环中绑定标识符时,您实际上正在操作封闭范围。
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
同样的协议为列表解析:
[num for num in range(1, 6)]
assert num == 5
令人兴奋的,我知道。任何人,凭借我们新发现的知识,我们可以确定您创建的lambda表达式是指在封闭范围内绑定的(单个)标识符。这应该使这个更有意义:
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)
这里是一个演示它更最酷的部分:
# 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)
所以解决这一点,当然,是让一个新的封闭范围为您要绑定的每个number
。在Python中,您可以使用模块,类和函数创建新的封闭范围。通常只使用函数为另一个函数创建新的封闭作用域。
在Python中,一个关闭是一个函数,返回另一个函数。有点像函数构造函数。在下面的例子中检查出get_fun
:
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)
由于get_fun
是一个函数,它就会拥有自己的内部范围。每次您用值调用get_fun
时,都会创建一个小表来跟踪其中的绑定;即它说:“在这个范围内,标识符指向已通过的事物。”这个范围在函数执行结束时会消失,除非有理由让它停下来。
如果你从一个范围内返回一个函数,那么这就是“范围表”部分存在的一个很好的原因 - 当你调用它时,你返回的函数可以引用该范围表中的东西稍后的。因此,在get_fun
内创建fun
时,Python会告诉fun
约get_fun
的范围表,其中fun
在需要时会保持方便。
您可以在Python docs on the execution model中阅读更多关于细节和技术术语(我稍微软化了一下)的内容。您也可以通过print fun.__closure__
查看函数引用的封闭范围的部分。在上文中,我们看到了参考value
,这恰好是一个int:不是[])
# 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>,)
很酷。这是“黑客”记录在任何地方?有没有更好的方法来做咖喱? 另外,请不要再提你的旋转床。 – 2009-01-17 02:02:50