python - 局部范围,超出封闭范围

标签 python python-3.x closures

为什么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/

相关文章:

python - 使用一对键创建值的并集

rust - 为什么 `std::mem::drop` 与高级特征边界中的闭包 |_|() 不完全相同?

swift - Realm IOS 类型转换结果关闭

javascript - 关闭原型(prototype)?

python - 运行 IPyhon.widgets 时没有名为 'ipywidgets' 的模块错误

python - 在 Python 中对字典列表中的数据进行排序和组合

python - 使用 BeautifulSoup 获取样式属性

Python:无法摆脱 TypeError:+ 不支持的操作数类型: 'NoneType' 和 'NoneType'

类属性中的Python循环导入

python - 只获取最后的回溯而不使用 None 的 raise?