闭包的一个经典例子

闭包的一个经典例子
例子:

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

  

posted @ 2017-09-07 17:38  几度夏  Views(674)  Comments(0Edit  收藏  举报