为了账号安全,请及时绑定邮箱和手机立即绑定

本地范围,超出了封闭范围

本地范围,超出了封闭范围

繁星点点滴滴 2021-03-29 13:29:36
为什么用lambda函数获取值列表i = 4。在调用lambda期间,不包含封闭范围。函数f已完成工作并返回控件(变量i不存在)。def f():    L = []    for i in range(5):         L.append(lambda x: i ** x)     return LL = f()L[0]def f1(N):    def f2(X):        return X**N    return f2f=f1(2) f (3)   9g = f1(3)g(3)27f(3)9
查看完整描述

2 回答

?
慕的地8271018

TA贡献1796条经验 获得超4个赞

Python使用闭包捕获对原始变量的引用。这些lambda对象保留了对i名称的引用,可以通过该引用访问值。这意味着i变量在f完成后将继续存在。


您可以.__closure__在lambda对象的元组中内省此闭包;函数具有相同的属性:


>>> 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

这也是列表中所有lambda都L引用value4而不是0到4的原因。它们都引用相同的闭包:


>>> L[0].__closure__[0] is L[1].__closure__[0]

True

闭包引用变量,而不是定义闭包时该变量的值。循环的i最后一次设置为4,因此在查找时,对于列表中的所有lambda,都会找到ilambda闭包4。


如果您希望lambdai在循环期间引用value,请在关键字参数中捕获它:


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

闭包引用特定命名空间中的变量;每次您调用函数时,都会创建一个新的本地名称空间,因此每个闭包都i在create_lambda与的其他调用不同的单独名称空间中引用create_lambda。


查看完整回答
反对 回复 2021-04-02
  • 2 回答
  • 0 关注
  • 132 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信