Have Python 2.7 functions remember value and not reference? Closure Weirdness

こ雲淡風輕ζ 提交于 2019-12-22 11:10:58

问题


I'm trying to return from a function a list of functions, each of which uses variables from the outside scope. This isn't working. Here's an example which demonstrates what's happening:

a = []
for i in range(10):
    a.append(lambda x: x+i)
a[1](1) # returns 10, where it seems it should return 2

Why is this happening, and how can I get around it in python 2.7 ?


回答1:


The i refers to the same variable each time, so i is 9 in all of the lambdas because that's the value of i at the end of the loop. Simplest workaround involves a default argument:

lambda x, i=i: x+i

This binds the value of the loop's i to a local variable i at the lambda's definition time.

Another workaround is to define a lambda that defines another lambda, and call the first lambda:

(lambda i: lambda x: x+i)(i)

This behavior makes a little more sense if you consider this:

def outerfunc():

    def innerfunc():
        return x+i

    a = []
    for i in range(10):
        a.append(innerfunc)
    return a

Here, innerfunc is defined once, so it makes intuitive sense that you are only working with a single function object, and you would not expect the loop to create ten different closures. With a lambda it doesn't look like the function is defined only once, it looks like you're defining it fresh each time through the loop, but in fact it is functionally the same as the the long version.




回答2:


Because i isn't getting evaluated when you define the anonymous function (lambda expression) but when it's called. You can see this by adding del i before a[1](1): you'll get NameError: global name 'i' is not defined on the a[1](1) line.

You need to fix the value of i into the lambda expression every time, like so:

a = [lambda x, i=i: x+i for i in range(10)]
a[1](1) # returns 2



回答3:


Another, more general solution - also without lambdas:

import operator
from functools import partial
a = []
for i in range(10):
    a.append(partial(operator.add, i))
a[1][(1) # returns 2

The key aspect here is functools.partial.



来源:https://stackoverflow.com/questions/6737112/have-python-2-7-functions-remember-value-and-not-reference-closure-weirdness

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!