美文网首页程序员
Python干货-函数式编程之闭包

Python干货-函数式编程之闭包

作者: 东南有大树 | 来源:发表于2018-10-28 15:57 被阅读15次

    返回函数

    高阶函数不仅可以返回值,还可以返回一个函数

    示例:

    def sum_func(*args):
        def sum():
            ax = 0
            for n in args:
                ax = ax + n
            return ax
        return sum
    

    上例中的sum_func函数内部另定义一个函数sum,sum函数被return返回,并没有被调用执行,所以返回的结果是sum函数的引用地址,可以用变量来接收这个引用对象

    # 获得sum_func函数返回的函数对象
    _func = sum_func(2,3,4)
    # 查看这个对象
    _func
    
    <function __main__.sum_func.<locals>.sum()>
    

    从输出上来看,变量_func是一个方法名,而要调用方法则需要在方法名后面添加一对括号

    # 调用返回的函数
    _func()
    
    9
    

    ok,这里调用了返回的函数,并且输出了2+4+5的值。问题是,参数2, 4, 5是sum_func()的参数,_func()如何获得这些函数呢?这里需要提出闭包的概念

    闭包(Closure):内部函数可以引用外部函数的参数和局部变量,当外部函数返了内部回函数时,相关参数和变量都保存在返回的函数中

    注意:因为每次调用外部函数的时候,都会重新定义一个内部函数,并将其返回,这样会在计算机内存里开辟不同的内存空间,创建不同的对象,虽然内部函数名字一样,但他们的引用地址其实不一样,所以如果多次调用外部函数返回内部函数,但其实返回的对象都是不一样的

    示例:

    _func1 = sum_func(1, 3, 5)
    _func2 = sum_func(1, 3, 5)
    
    print(_func1 is _func2)
    print('_func1 id', id(_func1))
    print('_func2 id', id(_func2))
    
    False
    _func1 id 4451353872
    _func2 id 4451354824
    

    闭包

    • 必须有一个内嵌函数(函数里定义的函数)——这对应函数之间的嵌套

    • 内嵌函数必须引用一个定义在闭合范围内(外部函数里)的变量——内部函数引用外部变量

    • 外部函数必须返回内嵌函数——必须返回那个内部函数

    注意:返回的函数并没有立刻执行,而是直到调用了f()才执行

    # 定义一个闭包
    
    def count():
        fs = [] 
        for i in range(1, 4):  # 循环三次,这里的i也算是闭合范围外的变量
            
            def f():  # 闭合范围
                 return i*i
                
            fs.append(f)  # 将f函数保存到fs中
        return fs
    
    f1, f2, f3 = count()  # 获得三个函数的引用
    

    再来看调用这三个函数的结果

    print(f1())
    print(f2())
    print(f3())
    
    9
    9
    9
    

    在得到第一个函数的时候,i的值是1;第二个函数返回的i则是2;第三个函数返回的i则是3;按常理来说,这三个函数的返回结果应该是1,4,9才对,而这里全都是9

    原因:i其实是闭全范围外的变量,i是一个引用对象,在三次循环后,i的值已经变成了三;此时调用返回的三个函数,它们内部所引用的i都指向了一个内存地址,也就是说是同一个引用对象,那此时的i当然是3,所以最终结果都是9

    返回闭包时牢记一点:返回函数不要引用任何循环变量,或者后续会发生变化的变量

    那如何解决这种情况呢?请看下面示例:

    def count():
        def f(j):
            def g():
                return j*j
            return g
        fs = []
        for i in range(1, 4):
            fs.append(f(i)) # f(i)立刻被执行,因此i的当前值被传入f()
        return fs
    
    f1, f2, f3 = count()
    print(f1())
    print(f2())
    print(f3())
    
    1
    4
    9
    

    原理:再创建一个函数,用该函数的参数绑定循环变量当前的值,无论该循环变量后续如何更改,已绑定到函数参数的值不变

    匿名函数

    上面的例子写得太过复杂,也不美观,如果一个函数代码块十分简洁,则可以用到匿名函数

    匿名函数使用关键字lambda,语法:lambda 参数 : 表达式,示例:

    _func = lambda x : x * x
    

    上例的代码表示创建一个匿名函数(函数没有名字),将此函数的引用赋值给变量_func

    冒号左边的x表示形参,如果有多个形参,则用逗号隔开

    冒号右边的是执行语句,需要注意的是匿名函数的执行语句只能有一行,如果执行语句有结果,则将结果返回,如果没有结果则返回None,返回结果不需要用到return

    下面来调用这个匿名函数:

    _func(2)
    
    4
    

    匿名函数的应用:

    def count():
        f = lambda j : lambda : j*j
        fs = []
        for i in range(1, 4):
            fs.append(f(i))
        return fs
    
    f1, f2, f3 = count()
    print(f1())
    print(f2())
    print(f3())
    
    1
    4
    9
    

    相关文章

      网友评论

        本文标题:Python干货-函数式编程之闭包

        本文链接:https://www.haomeiwen.com/subject/vezptqtx.html