请考虑下面的代码。
a = []
def func1(x):
return x
for i in range(3):
def func2():
return func1(i)
a.append(func2)
for k in range(3):
print(a[k]())
这会打印出
2
2
2
来自中的"别名的使用"http://gestaltrevision.be/wiki/python/aliases(最后一节)和中的"范围"部分http://gestaltrevision.be/wiki/python/functions_basics,我了解到函数参数实际上是传递的参数的别名。
因此,在中
def func1(x): return x
for i in range(3):
def func2(): return func1(i)
我推断,由于x将作为I的别名存储,即使每次执行循环时都会重新分配I,但它对别名x也无关紧要。
所以我期望前三行输出0,1,2,而不是2,2,2。
你能解释一下我做错了什么吗?感谢
您在这里创建了一个闭包func2,它使用封闭作用域中的变量i。func2的实例由DEF语句在FOR循环执行时创建。
然后在FOR循环退出后执行func2。在python中,循环变量在循环退出后不会被破坏。因此,在退出循环时,闭包使用封闭范围中i的当前值。
因此,在这段代码中,func1什么都不改变,没有它,结果将是一样的。
如果您希望您的代码以您想要的方式工作,请执行以下
def func2(i):
def func1():
return i
return func1
a = [func2(i) for i in range(3)]
for k in range(3):
print(a[k]()) # prints 0 1 2
为什么你的代码不起作用?这与对象何时绑定到闭包中的名称有关,即func1
。在代码中,参数x
到func1
在运行时绑定。因此,由于a
中的每个函数都有func1(i)
,并且打印时i
的值为2,因此您可以得到全部2。因此,解决方案是在编译时绑定它,即当func2
返回func1
时,i
已经绑定在func1
中。
执行此操作时:
for i in range(3):
def func2():
return func1(i)
您正在为[0, 1, 2]
中的每个i
"重新定义"您的func2
。生命的最终定义是:
def func2():
return func1(2)
就这么简单。不幸的是,它的行为并不像你所期望的那样。