以下是我从某人关于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 有没有人可以帮忙解释一下? 提前谢谢。
答案 0 :(得分:17)
循环不会在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))
答案 1 :(得分:4)
您不是在创建闭包。您正在生成一个函数列表,每个函数访问全局变量i
,该函数在第一个循环后等于2。因此,每次函数调用最终都会得到2 * 2.
答案 2 :(得分:1)
每个函数都访问全局i
。
from functools import partial
flist = []
for i in xrange(3):
def func(x, multiplier=None):
return x * multiplier
flist.append(partial(func, multiplier=i))