zoukankan      html  css  js  c++  java
  • 闭包的一个经典例子

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

    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

      

  • 相关阅读:
    使用.NET Core在RESTful API中进行路由操作
    基础教程:ASP.NET Core 2.0 MVC筛选器
    Angular 5和ASP.NET Core入门
    net core 使用tagHelper将 enum枚举类型转换为下拉列表select
    教你如何实现微信小程序与.net core应用服务端的无状态身份验证
    解决mssql localdb 中文乱码问题
    datagrid 新增,并行内编辑,提交保存
    合法的json数组字符串,转换json
    jfinal的回滚
    oracle 修改 字段名称
  • 原文地址:https://www.cnblogs.com/jiduxia/p/7490931.html
Copyright © 2011-2022 走看看