关于python闭包



下面是我从某人的博客中得到的一个关于python闭包的例子。我在python 2.7中运行它,得到了与预期不同的输出。

flist = []
for i in xrange(3):
    def func(x):
        return x*i
    flist.append(func)
for f in flist:
    print f(2)

我的预期输出为:0、2、4
但是输出是:4,4,4
有人可以帮忙解释吗
提前谢谢。

循环在Python中不引入作用域,因此所有三个函数都在同一个i变量上闭合,并在循环结束后引用其最终值,即2。

与我交谈过的几乎所有在Python中使用闭包的人似乎都被这一点所困扰。推论是,外部函数可以更改i,但内部函数不能(因为这会使i成为本地的,而不是基于Python语法规则的闭包)。

有两种方法可以解决这个问题:

# avoid closures and use default args which copy on function definition
for i in xrange(3):
    def func(x, i=i):
        return x*i
    flist.append(func)
# or introduce an extra scope to close the value you want to keep around:
for i in xrange(3):
    def makefunc(i):
        def func(x):
            return x*i
        return func
    flist.append(makefunc(i))
# the second can be simplified to use a single makefunc():
def makefunc(i):
    def func(x):
        return x*i
    return func
for i in xrange(3):
    flist.append(makefunc(i))
# if your inner function is simple enough, lambda works as well for either option:
for i in xrange(3):
    flist.append(lambda x, i=i: x*i)
def makefunc(i):
    return lambda x: x*i
for i in xrange(3):
    flist.append(makefunc(i))

您没有创建闭包。您正在生成一个函数列表,每个函数都访问全局变量i,该变量在第一个循环后等于2。因此,每个函数调用的结果都是2*2。

每个函数都访问全局i

functools.partial拯救:

from functools import partial
flist = []
for i in xrange(3):
    def func(x, multiplier=None):
        return x * multiplier
    flist.append(partial(func, multiplier=i))

最新更新