Local scope, beyond the scope of the enclosing

2019-01-15 11:18发布

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

1条回答
ゆ 、 Hurt°
2楼-- · 2019-01-15 12:11

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.

查看更多
登录 后发表回答