for循环中的lambda与闭包
问题引入
f = [lambda x: x*i for i in range(3)](与x无关)
i就是在闭包作用域(enclousing),而Python的闭包是 迟绑定 , 这意味着闭包中用到的变量的值,是在内部函数被调用时查询得到的
调用结果
当调用 func() 时,每循环一次,将 lam 函数的地址存到 fs 中。因为在每次循环中 lam函数都未绑定 i 的值,所以直到循环结束,i 的值为2,并将 lam 中所用到的 i 值定为 2 ,因此真正调用(例如f[0](2))的时候 i 值保持不变(为2),如下。
表达式用普通函数表示为:
f = [lambda :i*3 for i in range(3)](与x无关)
另一种将x换成i,就与传入的x值无关了。(这里 lambda 后面什么参数都不跟)
普通函数表示如下:
f = [lambda x, i=i:x*i for i in range(3)](与x有关)
变闭包作用域为局部作用域。其中,i=i前面的i就是局部作用域。
换种写法:
f = [lambda i=i: i*i for i in range(3)]
上面的表达式展开如下(为了更直观,替换了变量):
当调用 func() 时,每循环一次,将 lam 函数的地址存到 fs 中。但是在每次循环中 lam函数都将 i 值绑定到了 x 上,所以直到循环结束,不同地址的 lam 函数的 x 值为都不一样,因此真正调用(例如 f[0]())的时候 x 值都为当时被绑定的值。
但如果给 lam 函数传了参数,例如 f[0](8),那么所有的调用结果都为传参的平方。与上面解释并不冲突,只是将传的参数绑定到了 x 上。
f = [lambda x=i: i*i for i in range(3)]
和第二种好像,只是变了一个字符,那么结果就大不一样了。因为局部变量是x,i是闭包,会迟绑定。
对于上面的表达式,调用结果:
传不传参数都不影响结果。展开后:
虽然 lam 函数将 i 的值绑定到了 x 上,但函数体中并未使用 x,所以直到循环结束,i 的值变为2,才会在调用时使用。其实同第一种情况是一样的。