为什么lambda函数获取值列表i = 4.在调用lambda期间,封闭范围不存在。函数f已完成工作并返回控制(变量i不存在)。
def f():
L = []
for i in range(5):
L.append(lambda x: i ** x)
return L
L = f()
L[0]
def f1(N):
def f2(X):
return X**N
return f2
f=f1(2)
f (3)
9
g = f1(3)
g(3)
27
f(3)
9
答案 0 :(得分:9)
Python使用closures来捕获对原始变量的引用。 lambda
对象保留对i
名称的引用,通过该名称可以访问该值。这意味着i
变量在f
完成后继续存在。
你可以在lambda对象的.__closure__
元组中内省这个闭包;函数具有相同的属性:
>>> L[0].__closure__
(<cell at 0x1077f8b78: int object at 0x107465880>,)
>>> L[0].__closure__[0]
<cell at 0x1077f8b78: int object at 0x107465880>
>>> L[0].__closure__[0].cell_contents
4
这也是列表L
中所有 lambdas引用值4
而不引用数字0到4的原因。它们都引用< em>相同的关闭:
>>> L[0].__closure__[0] is L[1].__closure__[0]
True
闭包是指变量,而不是定义闭包时该变量的值。在循环结束时,i
最后设置为4
,因此当查找i
的lambda闭包4
时,将查找列表中的所有lambda。
如果您希望lambda在循环期间引用i
的值,请在关键字参数中捕获它:
def f():
L = []
for i in range(5):
L.append(lambda x, i=i: i ** x)
return L
现在i
是lambda的局部变量,而不是闭包。
或者,创建一个全新的范围来绘制闭包:
def create_lambda(i):
return lambda x: i ** x
def f():
return [create_lambda(i) for i in range(5)]
现在create_lambda()
是一个新的作用域,它有自己的本地i
,用于引用lambda闭包。然后每个lambdas都有自己的闭包:
>>> L[0].__closure__[0] is L[1].__closure__[0]
False
Closures引用特定命名空间中的变量;每次调用函数时都会创建一个新的本地名称空间,因此每个闭包引用i
中create_lambda
的{{1}}与另一个名为create_lambda
的名称单独的名称空间。