【第十七天】闭包的用法

3.闭包

上面函数中,line()定义嵌套在另一个函数内部
如果函数的定义中引用了外部变量,会发生什么呢?

def line_conf():
    b = 15
    def line(x):
        return 2*x + b
    b = 5
    return line       #返回函数对象

if __name__ == '__main__':
    my_line = line_conf()
    print(my_line(5))  #打印15

可以看到,line()定义的隶属程序块中引用了高层级的变量b
b的定义并不在line()的内部,而是一个外部对象
我们称b为line()的环境变量,尽管b位于line()定义的外部
但当line被函数line_conf()返回时,还是会带有b的信息

一个函数的它的环境变量合在一起,就构成了一个闭包(Closure)
上面程序中,b分别在line()定义的前后有两次不同的赋值
上面的代码将打印15,也就是说,line()参照的是值为5的b值
因此,闭包中包含的是内部函数返回时的外部对象的值

在py中,所谓闭包是一个包含有环境变量取值的函数对象
环境变量取值被复制到函数对象的closure属性中
比如下面代码:

def line_conf():

    b = 15
    def line(x):
        return 2*x + b
    b = 5
return line        #返回函数对象

if __name__ == '__main__':
    my_line = line_conf()
    print(my_line.__closure__)
    print(my_line.__closure__[0].cell_contents)
(<cell at 0x1074379a8: int object at 0x10268f5d0>,)
5

可以看到,my_line()的closure属性中包含了一个元组
这个元组中的每个元素都是cell类型的对象
第一个cell包含的就是整数5,也就是我们返回闭包时的环境变量b的取值

闭包可以提高代码的可复用性,下面看四个函数:

def line1(x):
    return x + 1
def line2(x):
    return 4*x + 1
def line3(x):
    return 5*x + 10
def line4(x):
    return -2*x - 6

如果把上面的程序改为闭包,那么代码就会简单很多:

def line_conf(a,b):
    def line(x):
        return a*x + b
    return line
    
line1 = line_conf(1,1)
line2 = line_conf(4,5)
line3 = line_conf(5,10)
line4 = line_conf(-2,-6)

这个例子中,函数line()与环境变量a,b构成闭包
在创建闭包的时候,我们通过line_conf()的参数说明直线的参量
这样,我们就能复用同一个闭包,通过代入不同的数据来获得不同的直线函数
如y=x+1和y=4x+5,闭包实际上创建了一群形式相似的函数

除了复用代码,闭包还能起到减少函数参数的作用:

def curve_closure(a,b,c):
    def curve(x):
        return a*x**2 + b*x + c
    return curve
curve1 = curve_closure(1,2,1)

函数curve()是一个二次函数,它除了自变量x外
还有a,b,c三个参数,通过curve_closure()这个闭包
我们可以预设a,b,c三个参数,从而起到减参的效果

闭包的减参作用对于并行运算来说很有意义
在并行运算环境下,我们可以让每台电脑负责一个函数
把上一台电脑的输出和下一台电脑的输入串联起来
最终,我们像流水线一样工作,由于每台电脑只能接受一个输入
所以在串联之前,必须用闭包之类的方法把参数的个数降为1

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。