为什么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
最佳答案
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
中的所有 lambda 都引用值 4
,而不是数字 0 到 4。它们都引用相同的闭包:
>>> L[0].__closure__[0] is L[1].__closure__[0]
True
闭包引用变量,而不是定义闭包时该变量的值。在循环结束时,i
最后设置为 4
,因此在 lambda 闭包 4
中查找 i
时> 将被找到,对于您列表中的所有 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 闭包引用。然后每个 lambda 都有自己的闭包:
>>> L[0].__closure__[0] is L[1].__closure__[0]
False
闭包引用特定命名空间中的变量;每次调用一个函数时,都会创建一个新的本地命名空间,因此每个闭包都引用 create_lambda
中的 i
,与其他对 create_lambda
的调用在一个单独的命名空间中>.
关于python - 局部范围,超出封闭范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17167764/