局部范围,超出了包围的范围 [英] Local scope, beyond the scope of the enclosing

查看:90
本文介绍了局部范围,超出了包围的范围的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么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 )
9
g = f1(3)
g(3)
27
f(3)
9


解决方案

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



您可以在lambda对象上的 .__ closure __ tuple中内省这个闭包;函数具有相同的属性:

 >> L [0] .__ closure__ 
(< cell on 0x1077f8b78:int object at 0x107465880> ;,)
>>> L [0] .__ closure __ [0]
< cell at 0x1077f8b78:int object at 0x107465880>
>>>> L [0] .__ closure __ [0] .cell_contents
4

em> all lambdas L 是指值 4 ,而不是数字0

 >>> L [0] .__ closure __ [0] is L [1] .__ closure __ [0] 
True

闭包是指 变量,而不是定义闭包时该变量的值。在循环结束 i 最后设置为 4 ,所以当查找 i



>如果你想让你的lambdas在循环中引用 i 的值,用一个关键字参数捕获它:



<范围(5)中的i:pre> def f():
L = []
。 :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

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


Why lambda function to get the list of values ​​i = 4 .During the call lambda, enclosing scope does not exist. The function f has finished work and returned control (the variable i does not exist).

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 uses closures to capture references to the original variable. The lambda objects retain a reference to the i name, through which the value can be accessed. This means that the i variable continues to live on after f completes.

You can introspect this closure in the .__closure__ tuple on the lambda objects; functions have the same attribute:

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

This is also why all lambdas in your list L refer to the value 4, and not to the numbers 0 through to 4. They all refer to the same closure:

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

The closure refers to the variable, not to the value of that variable at the time the closure was defined. At the end of the loop i was last set to 4, so when looking up i in the lambda closure 4 will be found, for all lambdas in your list.

If you want your lambdas to refer to the value of i during the loop, capture it in a keyword argument:

def f():
    L = []
    for i in range(5): 
        L.append(lambda x, i=i: i ** x) 
    return L

Now i is a local variable to the lambda, not a closure.

Alternatively, create an entirely new scope from which to draw the closure:

def create_lambda(i):
    return lambda x: i ** x

def f():
    return [create_lambda(i) for i in range(5)]

Now create_lambda() is a new scope with it's own local i for the lambda closure to refer to. The lambdas then each have their own closures:

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

Closures refer to a variable in a specific namespace; each time you call a function a new local namespace is created, so each closure refers to i in create_lambda in a separate namespace from other calls to create_lambda.

这篇关于局部范围,超出了包围的范围的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆