如果lambda或者def在函数中定义,嵌套在一个循环之中,并且嵌套的函数引用了一个上层作用域的变量,该变量被循环所改变,所有在这个循环中产生的函数将会有相同的值——在最后一次循环中完成时被引用变量的值。
例如,下面的程序试图创建一个函数的列表,其中每个函数都记住嵌套作用域中当前变量i的值 。
>>>def makeActions():
... acts = []
... for i in range(5):
... acts.append(lanbda x:i ** x)
... return acts
...
>>>acts = makeActions()
>>>acts[0]
<function <lambda> at 0x012B16B0>
尽管这样,但这并不怎么有效:因为嵌套作用域中的变量在嵌套函数被调用时才进行查找,所以它们实际上记住的是同样的值。也就是说,我们将从裂变中的每个函数得到4的平方的函数,因为i对于在每一个列表中的函数都是相同的值4。
>>>acts[0](2)
16
>>>acts[2](2)
16
>>>acts[4](2)
16
这是在嵌套作用域的值和默认参数方面遗留的一种仍需要解释清楚的情况,而不是引用所在的嵌套作用域的值。也就是说,为了让这类代码能够工作,必须使用默认参数把当前的值传递给嵌套作用域的变量。因为默认参数是在嵌套函数创建时评估的(而不是在其稍后调用时),每一个函数记住了总觉得变量i的值。
>>>def makeActions():
... acts = []
... for i in range(5):
... acts.append(lambda x,i=i: i ** x)
... return acts
...
>>>acts = makeActions()
>>>acts[0](2)
0
>>>acts[2](2)
4
>>>acts[4](2)
16
这是一种相当隐晦的情况,但是它会在实际情况中发生,特别是在生成应用于GUI一些部件的回调处理函数的代码中(例如,按钮的事件处理)。