闭包的一个经典例子
例子:
def count(): fs = [] for i in range(1, 4): def f(): return i*i fs.append(f) return fs f1, f2, f3 = count()
你可能认为调用f1(),f2()和f3()结果应该是1,4,9,但实际结果全部都是 9
返回的fs的列表为[f,f,f],当执行f1,f2,f3=count()的时候,f1=f,f2=f,f3=f,这个时候变量i的值已经变成了3,所以最后结果都为9
原因就是当count()函数返回了3个函数时,这3个函数所引用的变量 i 的值已经变成了3。由于f1、f2、f3并没有被调用,所以,此时他们并未计算 i*i
- 解决方案一:
def count(): fs = [] for i in range(1, 4): def f(m=i): return m*m fs.append(f) return fs f1, f2, f3 = count()
分析:问题的产生是因为函数只在执行时才去获取外层参数i,若函数定义时可以获取到i,问题便可解决。而默认参数正好可以完成定义时获取i值且运行函数时无需参数输入的功能,所以在函数f()定义中改为f(m = i),函数f返回值改为m*m即可.
- 解决方案二:
def count(): fs = [] for i in range(1, 4): def f(i): return i*i fs.append(f(i))#f(i)立刻被执行,因此i的当前值被传入f() return fs f1, f2, f3 = count()
分析:s.append(f),只是将每一个f()的引用保存进了list,并没有进行对于i的计算,所以导致最后在运行了f(1)之后,i已经变为了3,所以会一样结果都为9.只要将这里改为fs.append(f(i))即可,这样就在这一步的时候已经进行了i*i的运算,将结果保存了,通过这一题可以注意到在python这门语言之中,f与f()的大区别。
- 解决方案三:
def count(): fs = [] def f(j): def g(): return j*j return g for i in range(1, 4): fs.append(f(i)) return fs f1, f2, f3 = count()
分析:f()函数它可以正确地返回一个闭包g,g所引用的变量j不是循环变量,因此将正常执行。
在count函数的循环内部,如果借助f函数,就可以避免引用循环变量i。
- 解决方案4:
def count(): fs = [] for i in range(1, 4): def f(): return i*i fs.append(f()) #f()直接计算出结果 return fs f1, f2, f3 = count()
分析:非闭包解决方案,每次循环的时候,将结果存入fs列表中,最终返回的是一个特定值得列表,而不是返回一个元素为函数的列表
参考资料:
https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001431835236741e42daf5af6514f1a8917b8aaadff31bf000