python中for循环中使用lambda表达式遇到的坑
在接手这个项目后,由于主要使用的语言都是python,故本着已有语言基础以用到就现学现用的想法使用python。于是就过了一遍基础语法,然后就开始了现学现用的过程,一开始关于cv的一些基本操作什么的还是能够解决的。直到最近被一个小bug困扰了很长时间,整个国庆都没有找出来(虽然有四天在画uml图,但是也是实在看那段代码看吐了,不想改了),才发现不了解语言特性还是会掉到坑里面。
- problem
我将我遇到的问题简化了:
step=3
j=[1,2,3]
f=[]
for i in range(step):
fx=lambda x:x*j[i]
f.append(fx)
print(f[0](2))
上面这段代码,按照我以其他语言的思维来看打印结果应该是2,但是打印结果却是6。原因是f中所有的函数都是为最后一次,引用的是同一个对象。那么怎样解决这个问题呢?
解决方法有很多种:
1.
step=3
j=[1,2,3]
f=[]
for i in range(step):
fx=lambda x,i=i:x*j[i]
f.append(fx)
print(f[0](2))
在lambda函数中添加默认参数循环索引
2.
step=3
j=[1,2,3]
f=[]
for i in range(step):
fx=lambda i:lambda x=i:x*j[i]
f.append(fx(i))
print(f[0](2))
用又一层的lambda进行封装,同样将循环索引当作参数传入。同理用def 定义函数进行封装也可以,但是适用场景有限了(不能在函数内的循环使用)。
- summary
这两种方法其实原理都一样,就是将lambda表达式中的索引变量固定下来。第二种方法甚至有些累赘,第一种方法比较简洁干脆。之所以出现这样的问题,是因为lambda表达式在执行的时候才会去寻找变量i,而这时所有的i变量已经都为3了(python 中for循环索引作用域并不止在循环内部)。这种问题感觉光盯着代码,乍一看还真就觉得自己没错。